Wrox Programmer Forums

Need to download code?

View our list of code downloads.

Go Back   Wrox Programmer Forums > XML > XSLT
Password Reminder
Register
Register | FAQ | Members List | Calendar | Search | Today's Posts | Mark Forums Read
XSLT General questions and answers about XSLT. For issues strictly specific to the book XSLT 1.1 Programmers Reference, please post to that forum instead.
Welcome to the p2p.wrox.com Forums.

You are currently viewing the XSLT section of the Wrox Programmer to Programmer discussions. This is a community of tens of thousands of software programmers and website developers including Wrox book authors and readers. As a guest, you can read any forum posting. By joining today you can post your own programming questions, respond to other developersí questions, and eliminate the ads that are displayed to guests. Registration is fast, simple and absolutely free .
DRM-free e-books 300x50
Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old March 6th, 2012, 01:26 PM
Authorized User
Points: 303, Level: 6
Points: 303, Level: 6 Points: 303, Level: 6 Points: 303, Level: 6
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jul 2010
Posts: 74
Thanks: 23
Thanked 0 Times in 0 Posts
Question how to group the sibling nodes to different group as the child nodes based on busines

XSLT version 1.0

My input xml file is below:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<ISA>
  <ST>
    <MTX>
      <MTX02>ATN: 12345679n</MTX02>
    </MTX>
    <MTX>
      <MTX02>--------------------------------------</MTX02>
    </MTX>
    <MTX>
      <MTX02>WTN: 100001</MTX02>
    </MTX>
    <MTX>
      <MTX02>--LST</MTX02>
    </MTX>
    <MTX>
      <MTX02>SA 4684 INDUSTRY R, Ray, BZ 987654</MTX02>
    </MTX>
    <MTX>
      <MTX02>LN Import Products</MTX02>
    </MTX>
    <MTX>
      <MTX02>LA 1 2 345 Pkway</MTX02>
    </MTX>
    <MTX>
      <MTX02>--BILL</MTX02>
    </MTX>
    <MTX>
      <MTX02>Spicy .............. Yes123</MTX02>
    </MTX>
    <MTX>
      <MTX02>Name ............. IMPOR GOODS</MTX02>
    </MTX>
    <MTX>
      <MTX02>Address Line 1 ... PO BOX 99999</MTX02>
    </MTX>
    <MTX>
      <MTX02>--------------------------------------</MTX02>
    </MTX>
    <MTX>
      <MTX02>WTN: 100002</MTX02>
    </MTX>
    <MTX>
      <MTX02>--LST</MTX02>
    </MTX>
    <MTX>
      <MTX02>SA 4685 INDUSTRY R, Ray, BZ 987655</MTX02>
    </MTX>
    <MTX>
      <MTX02>LN Import Products</MTX02>
    </MTX>
    <MTX>
      <MTX02>LA 2 3 456 Pkway</MTX02>
    </MTX>
    <MTX>
      <MTX02>--BILL</MTX02>
    </MTX>
    <MTX>
      <MTX02>Spicy .............. No345</MTX02>
    </MTX>
    <MTX>
      <MTX02>Name ............. IMPOR GOODS</MTX02>
    </MTX>
    <MTX>
      <MTX02>Address Line 1 ... PO BOX 888888</MTX02>
    </MTX>
    <MTX>
      <MTX02>--------------------------------------</MTX02>
    </MTX>
    <MTX>
      <MTX02>WTN: 100003</MTX02>
    </MTX>
    <MTX>
      <MTX02>--LST</MTX02>
    </MTX>
    <MTX>
      <MTX02>SA 3333 INDUSTRY R, Ray, BZ 333333</MTX02>
    </MTX>
    <MTX>
      <MTX02>LN Import Products</MTX02>
    </MTX>
    <MTX>
      <MTX02>LA 3 3 444 Pkway</MTX02>
    </MTX>
    <MTX>
      <MTX02>--BILL</MTX02>
    </MTX>
    <MTX>
      <MTX02>Spicy .............. None333</MTX02>
    </MTX>
    <MTX>
      <MTX02>Name ............. IMPOR GOODS</MTX02>
    </MTX>
    <MTX>
      <MTX02>Address Line 1 ... PO BOX 444444</MTX02>
    </MTX>
  </ST>
</ISA>
I need to group all the nodes between "--------------------------------------" to their "--------------------------------------", which means: after the first "--------------------------------------", till the second "--------------------------------------", all the nodes between them need to make as the child-nodes of the first "--------------------------------------"; then after the second "--------------------------------------" till the third "--------------------------------------", all the nodes between them need to make as the child-nodes of the second "--------------------------------------", and so on. We can not mass the blocks each other, we need to keep it to its own "--------------------------------------". There probably are hundreds of such blocks. And I also need to move/change the value of each node to their own MTX node, which means: for example,
Code:
<MTX>
  <MTX02>Address Line 1 ... PO BOX 444444</MTX02>
</MTX>
needs to change to
Code:
<MTX>Address Line 1 ... PO BOX 444444</MTX>
So the output xml should like below:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<ISA>
  <ST>
    <MTX>ATN: 12345679n</MTX>
    <Section-------------------------------------->
      <MTX>WTN: 100001</MTX>
      <MTX>--LST</MTX>
      <MTX>SA 4684 INDUSTRY R, Ray, BZ 987654</MTX>
      <MTX>LN Import Products</MTX>
      <MTX>LA 1 2 345 Pkway</MTX>
      <MTX>--BILL</MTX>
      <MTX>Spicy .............. Yes123</MTX>
      <MTX>Name ............. IMPOR GOODS</MTX>
      <MTX>Address Line 1 ... PO BOX 99999</MTX>
    </Section-------------------------------------->
    <Section-------------------------------------->
      <MTX>WTN: 100002</MTX>
      <MTX>--LST</MTX>
      <MTX>SA 4685 INDUSTRY R, Ray, BZ 987655</MTX>
      <MTX>LN Import Products</MTX>
      <MTX>LA 2 3 456 Pkway</MTX>
      <MTX>--BILL</MTX>
      <MTX>Spicy .............. No345</MTX>
      <MTX>Name ............. IMPOR GOODS</MTX>
      <MTX>Address Line 1 ... PO BOX 888888</MTX>
    </Section-------------------------------------->
    <Section-------------------------------------->
      <MTX>WTN: 100003</MTX>
      <MTX>--LST</MTX>
      <MTX>SA 3333 INDUSTRY R, Ray, BZ 333333</MTX>
      <MTX>LN Import Products</MTX>
      <MTX>LA 3 3 444 Pkway</MTX>
      <MTX>--BILL</MTX>
      <MTX>Spicy .............. None333</MTX>
      <MTX>Name ............. IMPOR GOODS</MTX>
      <MTX>Address Line 1 ... PO BOX 444444</MTX>
    </Section-------------------------------------->
  </ST>
</ISA>
Thank you in advance!

Last edited by JohnKiller; March 6th, 2012 at 04:33 PM.
Reply With Quote
  #2 (permalink)  
Old March 7th, 2012, 05:59 AM
Friend of Wrox
Points: 6,522, Level: 34
Points: 6,522, Level: 34 Points: 6,522, Level: 34 Points: 6,522, Level: 34
Activity: 50%
Activity: 50% Activity: 50% Activity: 50%
 
Join Date: Nov 2007
Location: Germany
Posts: 1,220
Thanks: 0
Thanked 237 Times in 236 Posts
Default

Here is an XSLT 1.0 example using a key to group those elements
Code:
<xsl:stylesheet
  version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>
  
  <xsl:key name="k1"
           match="ST/MTX[not(MTX02[not(translate(., '-', ''))])]"
           use="generate-id(preceding-sibling::MTX[MTX02[not(translate(., '-', ''))]][1])"/>
           
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy> 
  </xsl:template>  
  
  <xsl:template match="ST">
    <xsl:copy>
      <xsl:apply-templates 
        select="*[not(preceding-sibling::MTX/MTX02[not(translate(., '-', ''))])] |
                MTX[MTX02[not(translate(., '-', ''))]]"/>
    </xsl:copy>
  </xsl:template>
  
  <xsl:template match="MTX[MTX02[not(translate(., '-', ''))]]">
    <xsl:element name="Section{MTX02}">
      <xsl:apply-templates select="key('k1', generate-id())"/>
    </xsl:element>
  </xsl:template>
  
  <xsl:template match="MTX[not(MTX02[not(translate(., '-', ''))])]">
    <xsl:copy>
      <xsl:value-of select="MTX02"/>
    </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
Reply With Quote
The Following User Says Thank You to Martin Honnen For This Useful Post:
JohnKiller (March 7th, 2012)
  #3 (permalink)  
Old March 7th, 2012, 10:00 AM
Authorized User
Points: 303, Level: 6
Points: 303, Level: 6 Points: 303, Level: 6 Points: 303, Level: 6
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jul 2010
Posts: 74
Thanks: 23
Thanked 0 Times in 0 Posts
Default

Thank you so much Martin. Well, I know I have asked to much, but would you kindly give some notes of your codes? I have read the function like key, translate, but I cannot understand your codes very well to figure out how these work together.

And thank you again for the help.
Reply With Quote
  #4 (permalink)  
Old March 7th, 2012, 10:32 AM
Friend of Wrox
Points: 6,522, Level: 34
Points: 6,522, Level: 34 Points: 6,522, Level: 34 Points: 6,522, Level: 34
Activity: 50%
Activity: 50% Activity: 50% Activity: 50%
 
Join Date: Nov 2007
Location: Germany
Posts: 1,220
Thanks: 0
Thanked 237 Times in 236 Posts
Default

Well the pattern
MTX[MTX02[not(translate(., '-', ''))]]
is simply an attempt to identify the elements "MTX" which have an "MTX02" child element where the content contains nothing but '-' characters (as after removing any of them with translate nothing but the empty string remains).
If the number of '-' in all those elements is constant you can simplify that pattern to e.g.
MTX[MTX02 = '----------']
where obviously you need to put the exact number of characters you expect in the input in that string literal.

For the other MTX elements (i.e. those not having simply '-' characters) we build a key which maps the generated id of the immediately preceding sibling element with '----...' to those elements you want to be wrapped. That way, once we process the elements we want to be wrapper elements (i.e. all elements matching MTX[MTX02[not(translate(., '-', ''))]]), we can use key('k1', generate-id()) to find the elements following the wrapper element.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
Reply With Quote
The Following User Says Thank You to Martin Honnen For This Useful Post:
JohnKiller (March 7th, 2012)
  #5 (permalink)  
Old March 7th, 2012, 11:04 AM
Authorized User
Points: 303, Level: 6
Points: 303, Level: 6 Points: 303, Level: 6 Points: 303, Level: 6
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jul 2010
Posts: 74
Thanks: 23
Thanked 0 Times in 0 Posts
Default

Thank you, Martin.

The number of the dashes "-" is instant, what about the use attribute in the key function, what does the "generate-id(preceding-sibling::MTX[MTX02='--------------------------------------'][1])" mean?

And in the template match="ST" template, what is the select mean? select="*[not(preceding-sibling::MTX/MTX02='--------------------------------------')] |
MTX[MTX02='--------------------------------------']"/>
Reply With Quote
  #6 (permalink)  
Old March 7th, 2012, 11:22 AM
Friend of Wrox
Points: 6,522, Level: 34
Points: 6,522, Level: 34 Points: 6,522, Level: 34 Points: 6,522, Level: 34
Activity: 50%
Activity: 50% Activity: 50% Activity: 50%
 
Join Date: Nov 2007
Location: Germany
Posts: 1,220
Thanks: 0
Thanked 237 Times in 236 Posts
Default

In the ST template, we want to ensure we only process the elements that we want to be wrapper elements (i.e. all those MTX elements having an MTX02 child full of dashes) plus those elements that will not be wrapped (i.e. those elements not having a preceding element with dashes). That is done by the select.

Then in the template for the MTX elements with an MTX02 full of dashes we need a way to find the elements following it. That's what we use the key for. As for generate-id, see http://www.w3.org/TR/xslt#function-generate-id or any XSLT book. If you have never used keys before it might be difficult to grasp but I am sure there is plenty of explanation in XSLT books or event tutorials on the web like http://www.learn-xslt-tutorial.com/W...-with-Keys.cfm so you will need to take your time to understand that.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
Reply With Quote
The Following User Says Thank You to Martin Honnen For This Useful Post:
JohnKiller (March 7th, 2012)
  #7 (permalink)  
Old March 7th, 2012, 11:32 AM
Registered User
Points: 6, Level: 1
Points: 6, Level: 1 Points: 6, Level: 1 Points: 6, Level: 1
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Mar 2012
Posts: 2
Thanks: 0
Thanked 0 Times in 0 Posts
Default Newbie

Hello, I am new to the forum.
Reply With Quote
  #8 (permalink)  
Old March 7th, 2012, 11:52 AM
Authorized User
Points: 303, Level: 6
Points: 303, Level: 6 Points: 303, Level: 6 Points: 303, Level: 6
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jul 2010
Posts: 74
Thanks: 23
Thanked 0 Times in 0 Posts
Default

Thank you, Martin. No, I didn't use key before, so that is why I feel hard to understand it.

If I want to change the node name before the MTX nodes, what I should do? I tried to add another template, but it is never good. And if before the MTX there are other nodes need to deal with separately, what I should do? The input like:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<ISA>
  <ISA01>00</ISA01>
  <ISA02>01</ISA02>
  <ISA03>02</ISA03>
  <GS>
    <GS01>PR</GS01>
    <GS02>FTRPO</GS02>
    <GS03>MTVFTRPO</GS03>
    <ST>
      <ST01>855</ST01>
      <ST02>0001</ST02>
      <BAK>
        <BAK01>11</BAK01>
        <BAK02>AT</BAK02>
        <BAK03>117431</BAK03>
        <BAK04>20120306</BAK04>
      </BAK>
      <DTM>
        <DTM01>097</DTM01>
        <DTM02>20120306</DTM02>
        <DTM03>115654</DTM03>
      </DTM>
      <SI>
        <SI01>TI</SI01>
        <SI02>IQ</SI02>
        <SI03>E</SI03>
      </SI>
      <N1>
        <N101>BY</N101>
        <N103>25</N103>
        <N104>184A</N104>
      </N1>
      <PO1>
        <PO101>1</PO101>
        <PO102>1</PO102>
        <PO103>EA</PO103>
        <PO106>A6</PO106>
        <PO107>CSA</PO107>
      </PO1>
      <N9>
        <N901>ME</N901>
        <N902>MLT</N902>
      </N9>
      <MTX>
        <MTX02>ATN: 12345679n</MTX02>
      </MTX>
      <MTX>
        <MTX02>--------------------------------------</MTX02>
      </MTX>
      <!-- the rest are the same as original post -->
      <CTT>
         <CTT01>1</CTT01>
      </CTT>
    </ST>
  </GS>
</ISA>
For the ISA01 to ISA03 nodes, I would not need them in the output, ignore them, as well as the GS nodes. For the child nodes under ST, I need to deal with BAK(if BAK01='11', BAK02='AT', then we get the value of BAK03 as new node named TXNUM), DTM(if DTM01='097, then we get the value of DTM02 as the new node named 'DTSENT'), and N9(
Code:
<xsl:choose>
        <xsl:when test="N9[N901 = '1Q']/N903 = 'PRESPC' ">
          <PRESPC><xsl:value-of select="N9[N901 = '1Q']/N902"/></PRESPC>
          <PRESPD><xsl:value-of select="MTX[1]/MTX02"/></PRESPD>
        </xsl:when>
        <xsl:when test="N9[N901 = '1Q']/N903 = 'RESPC' ">
          <RESPC><xsl:value-of select="N9[N901 = '1Q']/N902"/></RESPC>
          <RESPD><xsl:value-of select="MTX[1]/MTX02"/></RESPD>
        </xsl:when>
        <xsl:otherwise>
          <PRESPC>000</PRESPC>
          <PRESPD>Completed</PRESPD>
        </xsl:otherwise>
      </xsl:choose>
). Then for the nodes MTX, we create a new node named "unparsed" as their parent. So the new output should like
Code:
<?xml version="1.0" encoding="UTF-8"?>
<response>
  <TXNUM>117431</TXNUM>
  <DTSENT>20120306115654</DTSENT>
  <PRESPC>000</PRESPC>
  <PRESPD>Completed</PRESPD>
  <unparsed>
    <MTX>ATN: 12345679n</MTX>
    <SECTION-------------------------------------->
      <MTX>WTN: 100001</MTX>
      <MTX>--LST</MTX>
      <MTX>SA 4684 INDUSTRY R, Ray, BZ 987654</MTX>
      <MTX>LN Import Products</MTX>
      <MTX>LA 1 2 345 Pkway</MTX>
      <MTX>--BILL</MTX>
      <MTX>Spicy .............. Yes123</MTX>
      <MTX>Name ............. IMPOR GOODS</MTX>
      <MTX>Address Line 1 ... PO BOX 99999</MTX>
    </SECTION-------------------------------------->
    <SECTION-------------------------------------->
<!-- as the same as we grouped -->
    </SECTION-------------------------------------->
  </unparsed>
</response>
I only used one template in one stylesheet. I never wrote several templates together. I tried to write another template to deal with the nodes before the MTX nodes. But the result is not good.

Thank you so much, Martin.

Last edited by JohnKiller; March 7th, 2012 at 12:09 PM.
Reply With Quote
  #9 (permalink)  
Old March 7th, 2012, 01:13 PM
Friend of Wrox
Points: 6,522, Level: 34
Points: 6,522, Level: 34 Points: 6,522, Level: 34 Points: 6,522, Level: 34
Activity: 50%
Activity: 50% Activity: 50% Activity: 50%
 
Join Date: Nov 2007
Location: Germany
Posts: 1,220
Thanks: 0
Thanked 237 Times in 236 Posts
Default

This is getting too long and too complicated for me to solve in a forum post. The idea with XSLT is to write a template for each element type you want to map, for instance with the approach taken in my sample (identity transformation template plus some templates for those elements needing different treatment) you can simply add e.g.
Code:
<xsl:template match="ISA01 | ISA02 | ISA03"/>
to suppress any copying of these elements to the result.

And then to transform the ISA element to response you can add
Code:
<xsl:template match="ISA">
  <response>
     <xsl:apply-templates/>
  </response>
</xsl:template>
The grouping of some of the children of the ST is difficult, with XSLT 2.0 you could do it with some elegance and shortness but if you are limited to 1.0 my suggestion with the bulky key becomes difficult to handle.

If so far all you have done is single template stylesheets then I am afraid the task you have is rather challenging or even too much. Good luck.
__________________
Martin Honnen
Microsoft MVP (XML, Data Platform Development) 2005/04 - 2013/03
My blog
Reply With Quote
The Following User Says Thank You to Martin Honnen For This Useful Post:
JohnKiller (March 7th, 2012)
  #10 (permalink)  
Old March 7th, 2012, 01:42 PM
Authorized User
Points: 303, Level: 6
Points: 303, Level: 6 Points: 303, Level: 6 Points: 303, Level: 6
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Jul 2010
Posts: 74
Thanks: 23
Thanked 0 Times in 0 Posts
Default

Thank you so much for your help and time, Martin.

I think probably I need to deal with the node which I do nothing about manually.(I know that would be a stupid way).

Thank you again!
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off
Trackbacks are Off
Pingbacks are On
Refbacks are Off

Similar Threads
Thread Thread Starter Forum Replies Last Post
Count of distinct nodes in a group anarleti XSLT 3 June 30th, 2010 03:39 AM
Trying to group child nodes aalbetski XSLT 3 November 18th, 2006 12:29 PM
Restart new group number in Group Footer sukarso Crystal Reports 2 October 13th, 2006 12:11 PM
Question within ASP business Rules. fkmfkm Classic ASP Basics 0 May 17th, 2005 10:33 PM
Group by , Sub Group by and Sum mateenmohd SQL Server 2000 1 March 29th, 2005 08:51 AM



All times are GMT -4. The time now is 03:56 AM.


Powered by vBulletin®
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
© 2013 John Wiley & Sons, Inc.