Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implementing Key Value Concept in XSLT

Tags:

xslt

xslt-1.0

I am working on XSLT, where I need to implement something as follows. My Source XML sample looks like this.

<?xml version="1.0" encoding="ISO-8859-1"?>
    <catalog>
        <cd>
            <title>A</title>  
            <title>B</title>
            <title>C</title>  
        </cd>
    </catalog>

Consider there is some key value pair list is there.

    Key         Value
    A           Algebra
    B           Biology
    C           Chemistry
    D           Data Analysis
    ---         ---

    ----        ---

I need to write an xslt such that for every occurance of key 'A', need to replace with appropriate value.

I also need to mention the list of Key value pairs in the same XSLT. Sample Output:

<Data>
    <Subject>Algebra</Subject>
    <Subject>Biology</Subject>
    <Subject>Chemistry</Subject>
 </Data>

Can any one help me out how to do it.

Thank you.

like image 312
Patan Avatar asked Jun 18 '12 04:06

Patan


People also ask

What is key XSLT?

XSLT key() Function The key() function returns a node-set from the document, using the index specified by an <xsl:key> element.

How does xsl key work?

The <xsl:key> element declares a named key — that is, a name-value pair assigned to a specified element in an XML document. The key is used with the key() function in XPath expressions to help you access the assigned elements in a complex XML document efficiently.

What are the various steps in XSLT processing?

xsl:apply-imports, xsl:apply-templates, xsl:attribute, xsl:call-template, xsl:choose, xsl:comment, xsl:copy, xsl:copy-of, xsl:element, xsl:fallback, xsl:for-each, xsl:if, xsl:message, xsl:number, xsl:processing-instruction, xsl:sort, xsl:text, xsl:value-of, xsl:variable.

What are the two 2 inputs of an XSLT processor?

The XSLT processor operates on two inputs: the XML document to transform, and the XSLT stylesheet that is used to apply transformations on the XML. Each of these two can actually be multiple inputs.


1 Answers

I. Simple XSLT 1.0 Solution

This transformation:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <my:codes>
   <code key="A" value="Algebra"/>
   <code key="B" value="Biology"/>
   <code key="C" value="Chemistry"/>
   <code key="D" value="Data Analysis"/>
 </my:codes>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match=
  "title/text()[. = document('')/*/my:codes/*/@key]">

  <xsl:value-of select=
   "document('')/*/my:codes/*[@key=current()]/@value"/>
 </xsl:template>
</xsl:stylesheet>

when applied on the provided XML document:

<catalog>
    <cd>
        <title>A</title>
        <title>B</title>
        <title>C</title>
    </cd>
</catalog>

produces the wanted, correct result:

<catalog>
   <cd>
      <title>Algebra</title>
      <title>Biology</title>
      <title>Chemistry</title>
   </cd>
</catalog>

Explanation:

This is the standard way of including inline XML node as a global element (child element of xsl:stylesheet) that belongs to a (non-empty) namespace, different than the xsl namespace.


II. More efficient XSLT 1.0 solution, using keys:

<xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:my="my:my">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>

     <my:codes>
       <code key="A" value="Algebra"/>
       <code key="B" value="Biology"/>
       <code key="C" value="Chemistry"/>
       <code key="D" value="Data Analysis"/>
     </my:codes>

     <xsl:key name="kCodeByName" match="code" use="@key"/>

     <xsl:template match="node()|@*">
      <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
     </xsl:template>

     <xsl:template match=
      "title/text()[. = document('')/*/my:codes/*/@key]">

      <xsl:variable name="vCur" select="."/>

      <xsl:for-each select="document('')">
          <xsl:value-of select=
           "key('kCodeByName', $vCur)/@value"/>
      </xsl:for-each>
     </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the same XML document (above), the same correct, wanted result is produced:

<catalog>
   <cd>
      <title value="Algebra"/>
      <title value="Biology"/>
      <title value="Chemistry"/>
   </cd>
</catalog>

Explanation:

Accessing data via the key() function is typically sub-linear -- often O(1) and is extremely faster than linear search (which is important if the number of nodes to be searched is big).

Accessing a node of one document via an index (xsl:key) while processing a node of another document is possible if the document containing the node to be looked-up is the current document. To access nodes from the other document, its root (or node of interest need to be saved and referenced off a variable.)


III. XSLT 2.0 solution:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vCodes">
  <codes>
   <code key="A" value="Algebra"/>
   <code key="B" value="Biology"/>
   <code key="C" value="Chemistry"/>
   <code key="D" value="Data Analysis"/>
  </codes>
 </xsl:variable>

 <xsl:key name="kCodeByName" match="code" use="string(@key)"/>

 <xsl:template match="node()|@*">
  <xsl:copy>
   <xsl:apply-templates select="node()|@*"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match=
  "title/text()[key('kCodeByName', ., $vCodes)]">

  <xsl:sequence select=
   "key('kCodeByName', ., $vCodes)/@value"/>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the same XML document (above), the same correct, wanted result is produced:

<catalog>
   <cd>
      <title value="Algebra"/>
      <title value="Biology"/>
      <title value="Chemistry"/>
   </cd>
</catalog>

Explanation:

Almost the same as the efficient XSLT 1.0 solution, but:

  1. In XSLT 2.0 a template match pattern can contain a variable reference.

  2. In XSLT 2.0 there is no need for acrobatic tricks manipulating the current and the indexed documents -- the 3rd argument of the key() function is to specify the tree whose index to use.

like image 142
Dimitre Novatchev Avatar answered Sep 29 '22 16:09

Dimitre Novatchev