0

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.

1 Answer 1

1

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Hi Martin, Thanks for the quick reply. I'd prefer to go for the first option, if I understand correctly, I can remove namespace: xmlns:wd="urn:com.cust.report/Supplier_Invoices_2" then find/replace all wd: with *
Ok, this works. <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" > <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="/*:Report_Data/*:Report_Entry/*:CF_LRV_Journal_line_group" > ... etc Thanks very much.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.