简体   繁体   中英

Append a repeated element name in XML using XSLT?

If I have an XML file that looks like this:

<properties>
    <property>
        <picture>http://example.com/image1.jpg</picture>
        <picture>http://example.com/image2.jpg</picture>
        <picture>http://example.com/image3.jpg</picture>
        <picture>http://example.com/image4.jpg</picture>
        <picture>http://example.com/image5.jpg</picture>
    </property>
</properties>

How would I go about transforming it to where each picture URL element is unique like this:

<properties>
    <property>
        <picture1>http://example.com/image1.jpg</picture1>
        <picture2>http://example.com/image2.jpg</picture2>
        <picture3>http://example.com/image3.jpg</picture3>
        <picture4>http://example.com/image4.jpg</picture4>
        <picture5>http://example.com/image5.jpg</picture5>
    </property>
</properties>

Am I correct in assuming that there must be the same amount of elements per even if some of the elements contain empty values (the number of picture URLs does vary by property)?

Use count(preceding-sibling::*)+1 to get the index of the current element.

Complete example:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- identity transform -->
<xsl:template match="node()|@*">
<xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>
</xsl:template>

<!-- override for picture elements to rename element -->
<xsl:template match="picture">
    <xsl:element name="{name()}{count(preceding-sibling::*)+1}">
        <xsl:apply-templates select="node()|@*"/>
    </xsl:element>
</xsl:template>

</xsl:stylesheet>

This short and simple transformation (no axes used):

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

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

 <xsl:template match="picture">
   <xsl:element name="picture{position()}">
    <xsl:apply-templates/>
   </xsl:element>
 </xsl:template>
</xsl:stylesheet>

when applied to the provided XML document :

<properties>
    <property>
        <picture>http://example.com/image1.jpg</picture>
        <picture>http://example.com/image2.jpg</picture>
        <picture>http://example.com/image3.jpg</picture>
        <picture>http://example.com/image4.jpg</picture>
        <picture>http://example.com/image5.jpg</picture>
    </property>
</properties>

produces the wanted, correct result :

<properties>
   <property>
      <picture1>http://example.com/image1.jpg</picture1>
      <picture2>http://example.com/image2.jpg</picture2>
      <picture3>http://example.com/image3.jpg</picture3>
      <picture4>http://example.com/image4.jpg</picture4>
      <picture5>http://example.com/image5.jpg</picture5>
   </property>
</properties>

Explanation :

  1. Overriding the identity rule for picture elements.

  2. Using AVT and the position() function within the name attribute of xsl:element .

  3. Use of xsl:strip-space .

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