Veljko
Veljko

Reputation: 1798

XSLT for-each always takes only one element

I have XML which contains multiple elements:

<?xml version="1.0" encoding="UTF-8"?>
<data>
<element>
 <ip>192.168.188.101</ip>
</element>
<element>
 <ip>192.168.188.100</ip>
</element>
</data>

I want to make it to this structure:

<SYNCDW>
<CIDWSet>
<CI>
<CINUM>192.168.188.101</CINUM>
</CI>
<CI>
<CINUM>192.168.188.100</CINUM>
</CI>
</CIDWSet>
</SYNCDW>

But always one element is processed, the first one, although I have for-each.

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <SyncCIDW xmlns="http://www.ibm.com/maximo">
            <xsl:attribute name="xsi:schemaLocation" namespace="http://www.w3.org/2001/XMLSchema-instance">http://www.ibm.com/maximo</xsl:attribute>
            <CIDWSet>
            <xsl:for-each select="*[local-name()='data' and namespace-uri()='']/*[local-name()='element' and namespace-uri()='']">

                    <CI>
                        <CINUM>
                            <xsl:value-of select="string(*[local-name()='data' and namespace-uri()='']/*[local-name()='element' and namespace-uri()='']/*[local-name()='ip' and namespace-uri()=''])"/>
                        </CINUM>
                    </CI>

            </xsl:for-each>
            </CIDWSet>
        </SyncCIDW>
    </xsl:template>
</xsl:stylesheet>

Why I am not getting processed all other elements but only the first one? Thank you in advance for help

Upvotes: 1

Views: 2201

Answers (1)

Mads Hansen
Mads Hansen

Reputation: 66714

A couple of things:

  • Inside of the xsl:for-each, the context switches to the element that you are iterating over (in this case, /data/element), so to select the ip element your XPath is relative from the /data/element that you are "standing on" and would simply be ip. The way you had it, it would be looking for /data/element/data/element/ip inside of the xsl:for-each and would not produce any values inside of the <CINUM>.
  • You can simplify your XPath expressions. If the elements you are addressing are not bound to a namespace, rather than a generic match on any element and a predicate matching the local-name() and namespace-uri()='', just use the simplified XPath data/element.
  • If you are creating a statically known attribute xsi:schemaLocation with a statically known value, just use the literal declaration inside of the SyncCIDW element literal.
  • If you are using xsl:value-of it will yield the string value of the selected node. There is no need for the string() function.

Changes applied to your stylesheet:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <SyncCIDW xmlns="http://www.ibm.com/maximo" 
                  xsi:schemaLocation="http://www.ibm.com/maximo">
            <CIDWSet>
                <xsl:for-each select="data/element">

                    <CI>
                        <CINUM>
                            <xsl:value-of select="ip"/>
                        </CINUM>
                    </CI>

                </xsl:for-each>
            </CIDWSet>
        </SyncCIDW>
    </xsl:template>
</xsl:stylesheet>

Upvotes: 2

Related Questions