Solved

XPATH XSL group by (or extend hierarchy)

Posted on 2013-11-12
7
268 Views
Last Modified: 2013-11-14
Hi - not sure how to describe here exactly what I am trying to do (from a terminology perspective) however I can show before and desired results.

Here is some XML:

<?xml version="1.0" encoding="utf-8" ?>
<Orders>
  <order id="1001">
    <order_id>1001</order_id>
      <customer_name>Acme Unlimited</customer_name>
      <customer_address>123 Maple Street, OH 123112</customer_address>
      <customer_phone>+61(2)9812-1122</customer_phone>
      <orderItems.orderItem_id>9000</orderItems.orderItem_id>
      <orderItems.orderItemName>My First Item</orderItems.orderItemName>
      <orderItems.orderItemType>My first item type</orderItems.orderItemType>
      <orderItems.orderItemQty>5</orderItems.orderItemQty>
   </order>
  <order id="1002">
    <order_id>1002</order_id>
      <customer_name>Smith and Co Pty</customer_name>
      <customer_address>456 Elm Street, OH 123112</customer_address>
      <customer_phone>+61(2)9812-1122</customer_phone>
      <orderItems.orderItem_id>9001</orderItems.orderItem_id>
      <orderItems.orderItemName>My First Item</orderItems.orderItemName>
      <orderItems.orderItemType>My first item type</orderItems.orderItemType>
      <orderItems.orderItemQty>5</orderItems.orderItemQty>
  </order>
  <order id="1002">
    <order_id>1002</order_id>
      <customer_name>Smith and Co Pty</customer_name>
      <customer_address>456 Elm Street, OH 123112</customer_address>
      <customer_phone>+61(2)9812-1122</customer_phone>
      <orderItems.orderItem_id>9002</orderItems.orderItem_id>
      <orderItems.orderItemName>My Second Item</orderItems.orderItemName>
      <orderItems.orderItemType>My second item type</orderItems.orderItemType>
      <orderItems.orderItemQty>4</orderItems.orderItemQty>
  </order>
  <order id="1002">
      <order_id>1002</order_id>
        <customer_name>Smith and Co Pty</customer_name>
        <customer_address>456 Elm Street, OH 123112</customer_address>
        <customer_phone>+61(2)9812-1122</customer_phone>
        <orderItems.orderItem_id>9003</orderItems.orderItem_id>
        <orderItems.orderItemName>My Third Item</orderItems.orderItemName>
        <orderItems.orderItemType>My third item type</orderItems.orderItemType>
        <orderItems.orderItemQty>3</orderItems.orderItemQty>
   </order>
</Orders>

Open in new window


I would like to transform it to a more hierarchal structure, which I assume its something like a group-by. Any ideas?

<Orders>
  <order id="1001">
    <order_id>1001</order_id>
      <customer_name>Acme Unlimited</customer_name>
      <customer_address>123 Maple Street, OH 123112</customer_address>
      <customer_phone>+61(2)9812-1122</customer_phone>
      <orderItems>
        <orderItem id="9000">
          <orderItem_id>9000</orderItem_id>
          <orderItemName>My First Item 01</orderItemName>
          <orderItemType>My first item 01 type</orderItemType>
          <orderItems.orderItemQty>5</orderItems.orderItemQty>
        </orderItem>
      </orderItems>
    </order>

  <order id="1002">
    <order_id>1002</order_id>
      <customer_name>Smith and Co Pty</customer_name>
      <customer_address>456 Elm Street, OH 123112</customer_address>
      <customer_phone>+61(2)9812-1122</customer_phone>
      <orderItems>
        <orderItem id="9001">
          <orderItems.orderItem_id>9001</orderItems.orderItem_id>
          <orderItemName>My First Item 02</orderItemName>
          <orderItemType>My first item 02 type</orderItemType>
          <orderItemQty>5</orderItemQty>
        </orderItem>
        <orderItem id="9002">
          <orderItem_id>9002</orderItem_id>
          <orderItemName>My Second Item 02</orderItemName>
          <orderItemType>My second item 02 type</orderItemType>
          <orderItemQty>4</orderItemQty>
        </orderItem>
        <orderItem id="9003">
          <orderItem_id>9003</orderItem_id>
          <orderItemName>My Third Item 02</orderItemName>
          <orderItemType>My third item 02 type</orderItemType>
          <orderItemQty>3</orderItemQty>
        </orderItem>
      </orderItems>
    </order>
</Orders>

Open in new window



I unfortunately don't have a lot of time to learn xslt so any quick help would be very much appreciated! Deadline looms .... :)

Bonus points if you provide example code on how to apply the transform using C#!!
0
Comment
Question by:designavenue
  • 4
  • 3
7 Comments
 
LVL 60

Accepted Solution

by:
Geert Bormans earned 395 total points
ID: 39643864
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">
    
    <xsl:key name="order" match="order" use="@id"/>
    <xsl:strip-space elements="*"/>
    <xsl:output indent="yes"/>
    
    <xsl:template match="node()">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="Orders">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="order[generate-id() = generate-id(key('order', @id)[1])]"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="order">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="node()[not(starts-with(name(), 'orderItems.'))]"/>
            <orderItems>
                <xsl:for-each select="key('order', @id)">
                    <orderItem id="{orderItems.orderItem_id}">
                        <xsl:apply-templates select="node()[starts-with(name(), 'orderItems.')]"/>
                    </orderItem>
                </xsl:for-each>
            </orderItems>
        </xsl:copy>
    </xsl:template>
    
</xsl:stylesheet>

Open in new window

0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 39643865
This technique uses Muenchian grouping explained very well at

http://www.jenitennison.com/xslt/grouping/muenchian.html

For C#, just google, that is what I would do
0
 

Author Closing Comment

by:designavenue
ID: 39646445
Thank you ! Works perfectly. Appreciate your help here.

Also how would I modify it to use:

    <order_id>1001</order_id>

instead of

  <order id="1001">

for the matching process??
0
Master Your Team's Linux and Cloud Stack

Come see why top tech companies like Mailchimp and Media Temple use Linux Academy to build their employee training programs.

 
LVL 60

Expert Comment

by:Geert Bormans
ID: 39646618
change the key from
   <xsl:key name="order" match="order" use="@id"/>
into
   <xsl:key name="order" match="order" use="order_id"/>

and each use of the key function from
   key('order', @id)
into
   key('order', order_id)
0
 

Author Comment

by:designavenue
ID: 39646902
Great thanks!

One final thing which will clear up all of my questions:

What do I do if there is a namespace on a tag. For example:

<Orders xmlns="http://www.whoopie.com/event">

Doesn't work when I apply the stylesheet. Any ideas?
0
 

Author Comment

by:designavenue
ID: 39646985
I figured that one out - by declaring the stylesheet like this:

<xsl:stylesheet version="1.0" exclude-result-prefixes="v2" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:v2="http://www.whoopie.com/event">

Had some fun turning literal matches to elements.

Is there any way to strip out the orderItems. prefix in the resulting last child nodes?
0
 
LVL 60

Expert Comment

by:Geert Bormans
ID: 39647257
if there is an xmlns attribute (technically it is not an attribute but a namespace declaration,
your xml elements are in a namespace, meaning they are essentialy different elements than the ones in the stylesheet. Your fix is right

Post me your latest stylesheet and I will remove the orderItems. prefix
0

Featured Post

Gigs: Get Your Project Delivered by an Expert

Select from freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely and get projects done right.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

We all know that functional code is the leg that any good program stands on when it comes right down to it, however, if your program lacks a good user interface your product may not have the appeal needed to keep your customers happy. This issue can…
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…
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.
This tutorial gives a high-level tour of the interface of Marketo (a marketing automation tool to help businesses track and engage prospective customers and drive them to purchase). You will see the main areas including Marketing Activities, Design …

786 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