1

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)?

1
  • You seem to be missing a word: "there must be the same amount of elements per ____ even if..." Commented Mar 8, 2012 at 23:31

2 Answers 2

3

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>
Sign up to request clarification or add additional context in comments.

3 Comments

@Kurt, you could also use position() instead of count(preceding-sibling::*)+1. Right Francis?
No, you cannot. It will count white space nodes as well, not only elements.
@FrancisAvila: Actually one can use position() in the AVT -- see my answer.
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.