Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

XPATH XSL group by (or extend hierarchy)

Posted on 2013-11-12
7
Medium Priority
?
276 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 1580 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
The article shows the basic steps of integrating an HTML theme template into an ASP.NET MVC project
This Micro Tutorial will teach you how to add a cinematic look to any film or video out there. There are very few simple steps that you will follow to do so. This will be demonstrated using Adobe Premiere Pro CS6.
Loops Section Overview
Suggested Courses
Course of the Month20 days, 17 hours left to enroll

810 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