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.

ayk
  • 7
  • 3
  • Which XSLT processor are you using? How do you use it? Saxon in its supported versions 11 and 12 has an option you can switch on e.g. on the command line with `-ns:##any` https://www.saxonica.com/html/documentation11/using-xsl/commandline/ "The value ##any declares that unprefixed names are treated as a test on the local name of the element only: they will match regardless of namespace." – Martin Honnen Jul 11 '23 at 21:44
  • To test I use `http://xsltransform.net/` website, and finally I use the XSLT to transform the XML using `TransformerFactory` in a java application. – ayk Jul 12 '23 at 13:18
  • If you really use XSLT 2 or later in the Java world then you are probably using some version and edition of Saxon; for its own API s9api the `XsltCompiler` class has a method https://www.saxonica.com/html/documentation11/javadoc/net/sf/saxon/s9api/XsltCompiler.html#setUnprefixedElementMatchingPolicy(net.sf.saxon.s9api.UnprefixedElementMatchingPolicy) to set the policy. Not sure whether there is or what is a good way to use it with the JAXP Transformer(Factory) API. – Martin Honnen Jul 12 '23 at 13:55

1 Answers1

1

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>
Yitzhak Khabinsky
  • 18,471
  • 2
  • 15
  • 21