jelle Kake
jelle Kake

Reputation: 27

Namespace as variable for document being processed with XSLT

Problem is as follows, we need to transform XML files, our customer sends us 4 different files, each with different name and each file has a unique namespace, however the elements within the document are the same.

Files are named; Supplier_Invoices_1, Supplier_Invoices_2, Supplier_Invoices_3 etc. without extension, but they are XML.

The namespace for for Supplier_Invoices_2 is:

xmlns:wd="urn:com.cust.report/Supplier_Invoices_2"

For Invoice_1:

"urn:com.cust.report/Supplier_Invoices_1" 

Invoice_3:

"urn:com.cust.report/Supplier_Invoices_3"

etc, etc..

Input - Example of Supplier_Invoices_2:

<?xml version='1.0' encoding='UTF-8'?>
<wd:Report_Data xmlns:wd="urn:com.cust.report/Supplier_Invoices_2">
    <wd:Report_Entry>
        <wd:CF_LRV_Journal_line_group>
            <wd:Invoice_Number>SI-00026584</wd:Invoice_Number>
            <wd:Supplier_s_Invoice_Number>19031275</wd:Supplier_s_Invoice_Number>
            <wd:Invoice_Date>2019-03-18-07:00</wd:Invoice_Date>
            <wd:Supplier wd:Descriptor="Company X">
                <wd:ID wd:type="WID">d4e89886417501a66aadebf4570da733</wd:ID>
                <wd:ID wd:type="Supplier_Reference_ID">SUP924</wd:ID>
                <wd:ID wd:type="Supplier_ID">S-00000461</wd:ID>
            </wd:Supplier>
            <wd:Transaction_Debit_minus_Credit>1956.92</wd:Transaction_Debit_minus_Credit>          
        </wd:CF_LRV_Journal_line_group>
    </wd:Report_Entry>
</wd:Report_Data>  

XSLT:

<xsl:stylesheet version="2.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:wd="urn:com.cust.report/Supplier_Invoices_2">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">        
     <xsl:param name="XSLPath" select="base-uri()"/>
        <message>
            <data>
                <xsl:for-each select="/wd:Report_Data/wd:Report_Entry/wd:CF_LRV_Journal_line_group" >
                    <Documents>
                        <row>
                            <path>
                                <xsl:value-of select="tokenize($XSLPath,'/')[last()]" />
                            </path>
                            <CardCode>
                                <xsl:value-of select="./wd:Supplier/wd:ID[@wd:type='Supplier_ID']"/>
                            </CardCode>
                        </row>
                    </Documents>
                    <Document_Lines>
                        <row>
                            <Price>
                                <xsl:value-of select="./wd:Transaction_Debit_minus_Credit" />
                            </Price>
                        </row>
                    </Document_Lines>
                </xsl:for-each>
            </data>
        </message>
    </xsl:template>
</xsl:stylesheet>  

Output:

<?xml version="1.0" encoding="UTF-8"?>
<message xmlns:wd="urn:com.cust.report/Supplier_Invoices_2">
   <data>
      <Documents>
         <row>
            <path>Supplier_Invoices_2</path>
            <CardCode>S-00000461</CardCode>
         </row>
      </Documents>
      <Document_Lines>
         <row>
            <Price>1956.92</Price>
         </row>
      </Document_Lines>
   </data>
</message>

My question, how can I set the namespace in my XSL document to be variable for the document it is processing?

I added xsl:param to my XSL. The top document top 5 lines look like so:

<xsl:stylesheet version="2.0"  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:wd="urn:com.cust.report/$npath" >
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:template match="/">        
     <xsl:param name="XSLPath" select="base-uri()"/>
     <xsl:param name="npath" select="tokenize($XSLPath,'/')[last()]" />

Output:

<?xml version="1.0" encoding="UTF-8"?>
<message xmlns:wd="urn:com.cust.report/$npath">
   <data/>
</message>

Any help would be greatly appreciated.

Upvotes: 0

Views: 188

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167571

In XSLT/XPath 2 and later you can use a namespace wildcard *:foo to select elements with local name foo in any namespace so if you use e.g. *:Report_Data instead of wd:Report_Data you should be able to process documents of the same structure but with different namespaces just fine.

As an alternative, you can use stylesheets in a chain where you normalize the namespace for the inputs in different namespaces to a common one so that you then use the common namespace in your second stylesheet.

Upvotes: 1

Related Questions