0

In xslt transformation below is the input xml.

    <root xmlns="test1">
    <Entries xmlns="test2">
        <root xmlns="test1">
            <LAT>1</LAT>
        </root>
        <root xmlns="test1">
            <LAT>2</LAT>
        </root>
    </Entries>
    <Entries xmlns="test2">
        <root xmlns="test1">
            <LAT>3</LAT>
        </root>
        <root xmlns="test1">
            <LAT>4</LAT>
        </root>
    </Entries>
</root>

The XSLT code i am using against this xml is.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:p="test1"
xmlns:r="test2"
                version="1.0">
  <xsl:template match="//*[local-name()='root']">
<xsl:element name="Test">
<xsl:for-each select="//p:root/r:Entries">

<xsl:variable name="i" select="position()"/>
       <xsl:for-each select="//p:root/r:Entries/p:root">
       <xsl:element name="{concat('imei', $i)}"> <xsl:element name="LAT"><xsl:value-of select="//*[local-name()='LAT']"/></xsl:element>

</xsl:element>
      </xsl:for-each>

      </xsl:for-each>
</xsl:element>
  </xsl:template> 
</xsl:stylesheet>

The result I wanted is :

<Test>
<imei1>
 <LAT>1</LAT>
</imei1>
<imei1>
 <LAT>2</LAT>
</imei1>
<imei2>
 <LAT>3</LAT>
</imei2>
<imei4>
 <LAT>4</LAT>
</imei4>
</Test>

The result I am getting is:

<Test>
<imei1>
    <LAT>1</LAT>
</imei1>
<imei1>
    <LAT>1</LAT>
</imei1>
<imei1>
    <LAT>1</LAT>
</imei1>
<imei1>
    <LAT>1</LAT>
</imei1>
<imei2>
    <LAT>1</LAT>
</imei2>
<imei2>
    <LAT>1</LAT>
</imei2>
<imei2>
    <LAT>1</LAT>
</imei2>
<imei2>
    <LAT>1</LAT>
</imei2>

The same value is repeating and looping twice, did i given the wrong xpath. The first loop is correctly executing twice as expected which we can see in the concatinated expression imei1 and imei2 is there but the second loop is executing twice the expected result count and giving same result.

ashok
  • 1,078
  • 3
  • 20
  • 63

1 Answers1

1

Because of your indiscriminate use of //, your inner instruction:

<xsl:for-each select="//p:root/r:Entries/p:root">

will process all r:Entries/p:root nodes in the entire XML document. And since this is nested inside the outer:

<xsl:for-each select="//p:root/r:Entries">

it will be instantiated twice, once for every r:Entries node in the XML. Every node, processed twice, results in twice as many nodes as there were to begin with.


Similarly, your:

<xsl:value-of select="//*[local-name()='LAT']"/>

selects all nodes in the XML document whose local name is "LAT" - and in XSLT 1.0, xsl:value-of will always return the value of the first one of these.


Another point worth mentioning: since you have declared both xmlns:p="test1" and xmlns:r="test2" (as you should), there is no need to use hacks like *[local-name()='LAT'], when you can use p:LAT.

Finally, don't use xsl:element where literal result element will suffice: e.g. instead of <xsl:element name="Test"> write <Test>.

michael.hor257k
  • 113,275
  • 6
  • 33
  • 51
  • Thank you I got the solution i was about to post the same solution. I got the solution because of your hint Thank you!!. This is the first time I tried XSLT so I thought of using XPATH like that. – ashok Dec 08 '18 at 18:37