mdslup
mdslup

Reputation: 105

XSLT: Using a map to change child elements

I have an XML file:

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <category id="Cat1" owner="Team1">
        <entry id="Ent1" owner="John">
            <title>This is Entry 1</title>
        </entry>
        <entry id="Ent2" owner="Matt">
            <title>This is Entry 2</title>
        </entry>
    </category>
    <category id="Cat2" owner="Team2">
        <entry id="Ent3" owner="Arnold">
            <title>This is Entry 3</title>
        </entry>
        <entry id="Ent4" owner="Jim">
            <title>This is Entry 4</title>
        </entry>
    </category>
 </root>

For each ENTRY element, I would like to change the value of its TITLE child element based on its @id attribute. I created the following XSLT, which first defines a map...The key of each map entry is the @id of the element whose title I want to change. The value of each map entry is what I want the value of the TITLE element (which is a child of ENTRY) to become:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    <!-- set up the map -->
    <xsl:variable name="map">
        <entry key="Ent1">Here is the first entry</entry>
        <entry key="Ent2">Here is the second entry</entry>
        <entry key="Ent3">Here is the third entry</entry>
        <entry key="Ent4">Here is the fourth entry</entry>
    </xsl:variable>
    <!-- identity transform -->
    <xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    </xsl:template>

    <!-- Problem area: use the key to set the attribute of the correct procedure -->
    <xsl:template match="entry">
        <title><xsl:value-of select="$map/entry[@key = current()/@id]"/></title>
    </xsl:template>
</xsl:stylesheet>

From my understanding, this is a 2 step process:

  1. Perform the identity transform
  2. Create a new template to change the TITLE elements

But this create a a bizarre output, which has replaced my entire ENTRY elements with the TITLE elements...it's as if everything got performed 1 step too high.

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <category id="Cat1">
      <title>Here is the first entry</title>
      <title>Here is the second entry</title>
      <title>Here is the third entry</title>
   </category>
   <category id="Cat2">
      <title>Here is the fourth entry</title>
      <title>Here is the fifth entry</title>
      <title>Here is the sixth entry</title>
   </category>
</root>

Is my map wrong somehow? Am I misunderstanding the new templates that I have to use after the identity transform?

Upvotes: 0

Views: 798

Answers (1)

michael.hor257k
michael.hor257k

Reputation: 117165

If you want to modify the title element, then your template should match title - not its parent element entry.

<xsl:template match="title">
    <title>
        <xsl:value-of select="$map/entry[@key = current()/../@id]"/>
    </title>
</xsl:template>

Alternatively, you would have to recreate the contents of entry before proceeding to the title child:

<xsl:template match="entry">
    <xsl:copy>
        <xsl:copy-of select="@*"/>
        <title>
            <xsl:value-of select="$map/entry[@key = current()/@id]"/>
        </title>
    </xsl:copy>
</xsl:template>

Upvotes: 1

Related Questions