?
Solved

XPATH XSL group by (or extend hierarchy)

Posted on 2013-11-12
7
Medium Priority
?
274 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

 
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: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering 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

Summary: Persistence is the capability of an application to store the state of objects and recover it when necessary. This article compares the two common types of serialization in aspects of data access, readability, and runtime cost. A ready-to…
The Confluence of Individual Knowledge and the Collective Intelligence At this writing (summer 2013) the term API (http://dictionary.reference.com/browse/API?s=t) has made its way into the popular lexicon of the English language.  A few years ago, …
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …
Suggested Courses
Course of the Month15 days, 15 hours left to enroll

741 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