Search code examples
xmlxsltxslt-2.0

xsl:for-each select does not work with xmlns="http://www.example.com/TBD" inside XML


I need some help with my XSLT-2.0 code.
This is XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">
        <xsl:param name="today" select="format-dateTime(current-dateTime(), '[Y0001]-[M01]-[D01]T[H1]:[m01]:[s01]')"/>
        <document>
            <xsl:for-each select="//Product">
                <Product>
                    <Productdetail>
                        <DocumentID>
                            <xsl:value-of select="./ProductNr"/>
                        </DocumentID>
                        <DocumentProd>
                            <xsl:value-of select=".//Account/DebitNr"/>
                        </DocumentProd>
                        <Date>
                            <xsl:value-of select="$today"/>
                        </Date>
                    </Productdetail>
                </Product>
            </xsl:for-each>
        </document>
    </xsl:template>
</xsl:stylesheet>

Here is xml

<?xml version="1.0" encoding="UTF-8"?>
<Products refSchemaFile="V11.xsd" xmlns="http://www.example.com/TBD">
    <Product>
        <Nr/>
        <ProductNr>837228</ProductNr>
        <Account>
            <Nr/>
            <DebitNr>21549</DebitNr>
        </Account>
    </Product>
    <Product>
        <Nr/>
        <ProductNr>837227</ProductNr>
        <Account>
            <Nr/>
            <DebitNr>21547</DebitNr>
        </Account>
    </Product>
    <Product>
        <Nr/>
        <ProductNr>837226</ProductNr>
        <Account>
            <Nr/>
            <DebitNr>21544</DebitNr>
        </Account>
    </Product>
</Products>

This is XSLT Result

<?xml version="1.0" encoding="UTF-8"?>
<document xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema"/>

But if I delete xmlns="http://www.example.com/TBD" from XML, then I am getting:

<?xml version="1.0" encoding="UTF-8"?>
<document xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <Product>
        <Productdetail>
            <DocumentID>837228</DocumentID>
            <DocumentProd>21549</DocumentProd>
            <Date>2021-02-21T22:40:18</Date>
        </Productdetail>
    </Product>
    <Product>
        <Productdetail>
            <DocumentID>837227</DocumentID>
            <DocumentProd>21547</DocumentProd>
            <Date>2021-02-21T22:40:18</Date>
        </Productdetail>
    </Product>
    <Product>
        <Productdetail>
            <DocumentID>837226</DocumentID>
            <DocumentProd>21544</DocumentProd>
            <Date>2021-02-21T22:40:18</Date>
        </Productdetail>
    </Product>
</document>

Why is xmlns="http://www.example.com/TBD" a problem, and what do I have to do to create a result with xmlns="http://www.example.com/TBD" inside the XML?


Solution

  • The xmlns=".." directive in the XML sets the namespace for this element and all of its children. Namespaces are often realized using a prefix on the element's name, like xmlns:fn="http://www.w3.org/2005/xpath-functions". To use an element in this namespace, you have to use <fn:funcXY>, for example.

    In your case, adding the following attribute to the xsl:stylesheet element of your XSLT will be sufficient:

    xpath-default-namespace="http://www.example.com/TBD"
    

    It sets the namespace for all XPath expressions that do not explicitly specify another namespace with the first method. Therefore the expressions will match without setting a prefix on all of your matching expressions.

    You can read more about namespaces here at this link, for example.