Search code examples
xmlxsltxml-namespaces

Match elements ignoring namespace using XSLT 2.0


I have below XML that has namespaces and I'm not able to match the elements:

<?xml version="1.0" encoding="utf-8"?>
<Template xsi:schemaLocation="Invoice_Summary_Template" Name="Invoice_Summary_Template" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="Invoice_Summary_Template">
    <Batches>
        <Collection>
            <Item>
                <Batch>
                    <Report Name="Invoice_Summary">
                        <Invoices>
                            <Invoice_Collection>
                                <Invoice Id="1">                                    
                                    <content>
                                        <misc>aaa</misc>
                                        <misc>bbb</misc>
                                    </content>                                    
                                </Invoice>
                                <Invoice Id="2">                                    
                                    <content>
                                        <misc>ccc</misc>                                        
                                    </content>
                                </Invoice>
                                <Invoice Id="2">                                    
                                    <content>
                                        <misc>ccc</misc>
                                        <misc>ddd</misc>
                                    </content>
                                </Invoice>
                            </Invoice_Collection>
                        </Invoices>
                    </Report>
                </Batch>                
            </Item>
        </Collection>
    </Batches>
</Template> 

From other posts I read that I have to add the above namespace into my XSLT. I tried, and my XSLT looks like this:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="xsi:Invoice_Collection">    
        <xsl:for-each-group select="Invoice" group-by="@Id">        
            <Item>
                <header>
                    <xsl:element name="invoice">
                        <xsl:attribute name="VAL">Id</xsl:attribute>
                        <xsl:value-of select="@Id"/>
                    </xsl:element>
                </header>               
            </Item>        
        </xsl:for-each-group>
</xsl:template>

</xsl:stylesheet>

I even added the xsi prefix to the for-each-group select as suggested by some other post. Unfortunately, this code still isn't working. My XSLT only works when I leave only the Template element with nothing else in my source XML.


Solution

  • Please try the following XSLT.

    Notable points:

    • The input XML elements are bound to a default namespace. That's why addition of the xpath-default-namespace="Invoice_Summary_Template"
    • No need to use xsi prefix in the template.
    • You would need to add a root element to make output XML well-formed.

    XSLT 2.0

    <?xml version="1.0"?>
    <xsl:stylesheet version="2.0"
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                    xpath-default-namespace="Invoice_Summary_Template"
                    exclude-result-prefixes="xsi">
    
        <xsl:output method="xml" version="1.0" encoding="UTF-8"
                    indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:template match="Invoice_Collection">
            <xsl:for-each-group select="Invoice" group-by="@Id">
                <Item>
                    <header>
                        <xsl:element name="invoice">
                            <xsl:attribute name="VAL">Id</xsl:attribute>
                            <xsl:value-of select="@Id"/>
                        </xsl:element>
                    </header>
                </Item>
            </xsl:for-each-group>
        </xsl:template>
    </xsl:stylesheet>
    

    Output

    <?xml version='1.0' encoding='UTF-8' ?>
    <Item>
      <header>
        <invoice VAL="Id">1</invoice>
      </header>
    </Item>
    <Item>
      <header>
        <invoice VAL="Id">2</invoice>
      </header>
    </Item>