?
Solved

XPATH XSL group by (or extend hierarchy)

Posted on 2013-11-12
7
Medium Priority
?
275 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
Technology Partners: 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

I was working on a PowerPoint add-in the other day and a client asked me "can you implement a feature which processes a chart when it's pasted into a slide from another deck?". It got me wondering how to hook into built-in ribbon events in Office.
Performance in games development is paramount: every microsecond counts to be able to do everything in less than 33ms (aiming at 16ms). C# foreach statement is one of the worst performance killers, and here I explain why.
In this video, Percona Solution Engineer Rick Golba discuss how (and why) you implement high availability in a database environment. To discuss how Percona Consulting can help with your design and architecture needs for your database and infrastr…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Suggested Courses

650 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