Solved

XML Style Sheet that generates unique names from sibling nodes with identical names

Posted on 2009-03-30
4
258 Views
Last Modified: 2013-11-18
Dear Experts:

We interface with an e-commerce site where Sales Orders are generated and exported to an XML file.  We transform that xml file, using a style sheet, that generates a second xml file.
This file is then imported to a relational db.  The  following code is a paired down example of the XML file that we receive, and must transform.  The problem comes in when we have to deal with the custom fields that may, or may not be, included in the XML file we receive.

In the element <customDocFields>,  we have up to six custom <field> elements that may be included in the XML we receive.  I say "may be", because these are user-defined fields and may be intialized.  If initalized, they appear in the XML, otherwise they do not.

We can have up to three <field> elements with a field type of "reseller_q" and three with a field type of "company_q".  Although the element tag ,<customDocfields> will always appear in the XML file we receive, the <field> elements may or may not.

What I am hoping to do, is ALWAYS generate six elements in our OUTPUT xml file, even when they don't all exist in the SOURCE xml file.  

<field> elements with a fieldType of "reseller_q", need to be mapped to child elements of the <docHeader> element with unique element names of their own.  The same is true for the <field> elements with a fieldType of "company_q".

What we need in our transformed XML file, is standardized output of six elements for the custom field names, and six field elements for the custom field text.  Again, whether they are in the SOURCE xml file or not.

It appears that I need some kind of for-each loop that generates 3 elements for each category of custom field.  Somehow the loop counter number is concatenated to the element name so we end up with:

  <reseller_q1_name> and also
  <reseller_q1_data>
  <company_q1_name>
  <company_q1_data>
 
  along with q2 and q3 elements for each of the above.

I have the same issue with the line items, but if someone can help me get over the hump understanding this, I believe I can apply the same concept there.

Any direction is greatly appreciated.

This is the Source XML file:
 

<?xml version="1.0" encoding="UTF-8"?>

<export_documents_response >

<documents>

 <document documentNumber="64794" documentType="Sales Order">

  <customDocFields>

   <field name="Cost Center" fieldType="reseller_q">"4600-000"</field>

   <field name="Invoice Number" fieldType="reseller_q">"0043001"</field>

   <field name="Shipping Notes" fieldType="reseller_q"/>

   <field name="Job ID" fieldType="company_q"/>

  </customDocFields>

  <itemList>

   <product lineItemNumber="1" productId="M004675190" >

    <customLineFields>

     <field name="Department" fieldType="reseller_qp"/>

     <field name="Field Test 2" fieldType="reseller_qp"/>

     <field name="Field Test 3" fieldType="reseller_qp"/>

     <field name="Contract Type" fieldType="company_qp"/>

     <field name="Length" fieldType="company_qp"/>

    </customLineFields>

   </product>

 </itemList>

 </document>

</documents>

</export_documents_response>
 

The data below is what we are trying to achieve.
 

<documents>

 <document> <docHeader>

   <reseller_q1_name>"Cost Center"</reseller_q1_name>

   <reseller_q1_data>"4600-000"</reseller_q1_data>

   <reseller_q2_name>"Invoice Number"</reseller_q2_name>

   <reseller_q2_data>"0043001"</reseller_q2_data>

   <reseller_q3_name>"Shipping Notes"</reseller_q3_name>

   </reseller_q3_data>

   <company_q1_name>"Job ID"</company_q1_name>

   </company_q1_data>

   </company_q2_name>

   </company_q2_data>

   </company_q3_name>

   </company_q3_data>

  </docHeader>

  <docLines>

   <reseller_qp1_name>"Department"</reseller_qp1_name>

   </reseller_qp1_data>

   <reseller_qp2_name>"Field Test 2"</reseller_qp2_name>

   </reseller_qp2_data>

   <reseller_qp3_name="Field Test 3"</reseller_qp3_name>

   </reseller_qp3_data>

  </docLines>

 <document>

</documents>
 
 

Below is the style sheet we currently use to transpose the SOURCE XML file.  We run into problems when there are multiple child nodes of the <customDocFields> and/or

<customLineFields> that have the same field type.
 

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0"

xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="export_documents_response">

<data>

<xsl:for-each select="documents/document">

 <docHeader>

  <documentNumber><xsl:value-of select="@documentNumber"/></documentNumber>

  <customDocFields_fieldType_reseller_q_name><xsl:value-of select=" _

    customDocFields/field /@fieldType='reseller_q']/@name"/> _

   </customDocFields_fieldType_reseller_q_name>

</docHeader>

</xsl:for-each>

<xsl:for-each select="documents/document/itemList/product">

 <docLines>

  <documentNumber><xsl:value-of select="../../@documentNumber"/></documentNumber>

  <customLineFields_fieldType_reseller_qp_name><xsl:value-of select="customLineFields/field _

    [@fieldType='reseller_qp']/@name"/> 

  </customLineFields_fieldType_reseller_qp_name>

  <customLineFields_fieldType_reseller_qp> _

   <xsl:value-of select="customLineFields/field[@fieldType='reseller_qp']"/>

   </customLineFields_fieldType_reseller_qp>

 </docLines>

</xsl:for-each>

</data>

</xsl:template>

</xsl:stylesheet>

Open in new window

0
Comment
Question by:csaintaz
  • 2
  • 2
4 Comments
 
LVL 60

Accepted Solution

by:
Geert Bormans earned 500 total points
ID: 24021970
There is a way to use lookup tables in XSLT
For that you need to allow the document() function (that is sometimes switched off, depending on the library you use)
Using such a lookup table in the XSLT (look at the map: namespace in my example) you can use document('') to point inside the XSLT,
you can actually build an iterator, without recursion (that would be the alternative)

I have built part of the solution,
now you can either copy or put everything in a named template

good luck

Geert
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0"

    xmlns:map="urn:internal:xslt:iterator"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

     exclude-result-prefixes="map">

    <xsl:output indent="yes"/>

    <xsl:strip-space elements="*"/>

    <xsl:template match="export_documents_response">

        <data>

            <xsl:apply-templates/>

        </data>

    </xsl:template>

    <xsl:template match="documents">

        <documents>

            <xsl:apply-templates select="document"/>

        </documents>

    </xsl:template>

    <xsl:template match="document">

        <document>

            <docHeader>

                <documentNumber><xsl:value-of select="@documentNumber"/></documentNumber>

                <xsl:variable name="this-doc" select="."/>

                <xsl:for-each select="document('')//map:iterator/map:value">

                    <xsl:variable name="this-param"><xsl:value-of select="."/></xsl:variable>

                    <xsl:element name="reseller_q{$this-param}_name">

                        <xsl:value-of select="$this-doc/customDocFields/field[@fieldType = 'reseller_q'][position() = $this-param]/@name"/>

                    </xsl:element>

                    <xsl:element name="reseller_q{$this-param}_data">

                        <xsl:value-of select="$this-doc/customDocFields/field[@fieldType = 'reseller_q'][position() = $this-param]"/>

                    </xsl:element>

                </xsl:for-each>

                <xsl:for-each select="document('')//map:iterator/map:value">

                    <xsl:variable name="this-param"><xsl:value-of select="."/></xsl:variable>

                    <xsl:element name="company_q{$this-param}_name">

                        <xsl:value-of select="$this-doc/customDocFields/field[@fieldType = 'company_q'][position() = $this-param]/@name"/>

                    </xsl:element>

                    <xsl:element name="company_q{$this-param}_data">

                        <xsl:value-of select="$this-doc/customDocFields/field[@fieldType = 'company_q'][position() = $this-param]"/>

                    </xsl:element>

                </xsl:for-each>

            </docHeader>

            <xsl:apply-templates select="itemList/product"/>

        </document>

    </xsl:template>

    <xsl:template match="temList/product">

        <docLines>

            <documentNumber><xsl:value-of select="../../@documentNumber"/></documentNumber>

<!--            <customLineFields_fieldType_reseller_qp_name><xsl:value-of select="customLineFields/field _

                [@fieldType='reseller_qp']/@name"/> 

            </customLineFields_fieldType_reseller_qp_name>

            <customLineFields_fieldType_reseller_qp> _

                <xsl:value-of select="customLineFields/field[@fieldType='reseller_qp']"/>

            </customLineFields_fieldType_reseller_qp>

-->        </docLines>

    </xsl:template>
 

    <map:iterator>

        <map:value>1</map:value>

        <map:value>2</map:value>

        <map:value>3</map:value>

    </map:iterator>

    

    

</xsl:stylesheet>

Open in new window

0
 

Author Comment

by:csaintaz
ID: 24023525
Thanks Geert,

I will give it a try and let you know how it works out.
0
 

Author Closing Comment

by:csaintaz
ID: 31564418
Geert,
The solution you provided worked great.  I really appreciate  the time you spent.  Thamk you.
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 24040808
welcome
0

Featured Post

Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
c#, split 12 78
microsoft access - xml 10 29
parse convert xml feed to text (python) 2 32
ASP.NET reading ATOM 2 27
Preface In the first article: A Better Website Login System (http://www.experts-exchange.com/A_2902.html) I introduced the EE Collaborative Login System and its intended purpose. In this article I will discuss some of the design consideratio…
Browsing the questions asked to the Experts of this forum, you will be amazed to see how many times people are headaching about monster regular expressions (regex) to select that specific part of some HTML or XML file they want to extract. The examp…
Viewers will learn about the regular for loop in Java and how to use it. Definition: Break the for loop down into 3 parts: Syntax when using for loops: Example using a for loop:
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now