简体   繁体   中英

XSLT Transforming when having multiple nodes with the same name

I have an issue regarding getting the values of child elements of each element in a list of nodes with the same name (the "b"-element in the example below).

My attempts at googling (and searching this site) has yielded no results.

My actual XML is more verbose, but I've made a simplified version which does reproduce the result. It looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<a>
  <b>
    <c>
      <d>Value 1</d>
    </c>
  </b>
  <b>
    <c>
      <d>Value 2</d>
    </c>
  </b>
  <b>
    <c>
      <d>Value 3</d>
    </c>
  </b>
</a>

I wish to transform it to a structure like this:

<?xml version="1.0" encoding="UTF-8"?>
<docRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="our.urn.namespace our.xsd">
   <subEl>
      <value>Value 1</value>
   </subEl>
   <subEl>
      <value>Value 2</value>
   </subEl>
   <subEl>
      <value>Value 3</value>
   </subEl>
</docRoot>

My XSLT looks like this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/a/b/c/d/text()">
    <xsl:element name="value">
      <xsl:value-of select="/a/b/c/d"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="/a/b/c">
    <xsl:element name="subEl">
      <xsl:apply-templates select="./d/text()"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="/">
    <xsl:element name="docRoot">
      <xsl:attribute name="xsi:schemaLocation">our.urn.namespace our.xsd</xsl:attribute>
      <xsl:apply-templates select="/a/b/c"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

However, this gives the following result:

<?xml version="1.0" encoding="UTF-8"?>
<docRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="our.urn.namespace our.xsd">
   <subEl>
      <value>Value 1</value>
   </subEl>
   <subEl>
      <value>Value 1</value>
   </subEl>
   <subEl>
      <value>Value 1</value>
   </subEl>
</docRoot>

Obviously I don't select this properly. Does anyone know the proper xpath to get the desired output?

NB: I also made an attempt where the template matching "/" had

   <xsl:apply-templates select="/a/b"/>

instead of what's in the example above, and then I used for-each in the template it applied, but no change in the result. This to my mind indicates that the issue is with the xpath. Also I'd rather prefer not using for-each for the sake of maintainability.

Try merging your first two template-matches into:

<xsl:template match="/a/b/c">
  <xsl:element name="subEl">
    <xsl:element name="value">
      <xsl:value-of select="./d/text()"/>
    </xsl:element>
  </xsl:element>
</xsl:template>

Edit: if you want something closer to your approach you could do

  <xsl:template match="/a/b/c/d">
    <xsl:element name="value">
      <xsl:value-of select="text()"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="/a/b/c">
    <xsl:element name="subEl">
      <xsl:apply-templates select="./d"/>
    </xsl:element>
  </xsl:template>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM