Wrox Programmer Forums
Go Back   Wrox Programmer Forums > XML > XSLT
| 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 software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
  #1 (permalink)  
Old March 6th, 2012, 02: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 05:33 PM..
  #2 (permalink)  
Old March 7th, 2012, 06:59 AM
Friend of Wrox
Points: 6,676, Level: 34
Points: 6,676, Level: 34 Points: 6,676, Level: 34 Points: 6,676, Level: 34
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Nov 2007
Location: Germany
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 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
The Following User Says Thank You to Martin Honnen For This Useful Post:
JohnKiller (March 7th, 2012)
  #3 (permalink)  
Old March 7th, 2012, 11: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.
  #4 (permalink)  
Old March 7th, 2012, 11:32 AM
Friend of Wrox
Points: 6,676, Level: 34
Points: 6,676, Level: 34 Points: 6,676, Level: 34 Points: 6,676, Level: 34
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Nov 2007
Location: Germany
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 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
The Following User Says Thank You to Martin Honnen For This Useful Post:
JohnKiller (March 7th, 2012)
  #5 (permalink)  
Old March 7th, 2012, 12:04 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, 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='--------------------------------------']"/>
  #6 (permalink)  
Old March 7th, 2012, 12:22 PM
Friend of Wrox
Points: 6,676, Level: 34
Points: 6,676, Level: 34 Points: 6,676, Level: 34 Points: 6,676, Level: 34
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Nov 2007
Location: Germany
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 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
The Following User Says Thank You to Martin Honnen For This Useful Post:
JohnKiller (March 7th, 2012)
  #7 (permalink)  
Old March 7th, 2012, 12:32 PM
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.
  #8 (permalink)  
Old March 7th, 2012, 12:52 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, 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 01:09 PM..
  #9 (permalink)  
Old March 7th, 2012, 02:13 PM
Friend of Wrox
Points: 6,676, Level: 34
Points: 6,676, Level: 34 Points: 6,676, Level: 34 Points: 6,676, Level: 34
Activity: 0%
Activity: 0% Activity: 0% Activity: 0%
 
Join Date: Nov 2007
Location: Germany
Posts: 1,243
Thanks: 0
Thanked 245 Times in 244 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
The Following User Says Thank You to Martin Honnen For This Useful Post:
JohnKiller (March 7th, 2012)
  #10 (permalink)  
Old March 7th, 2012, 02: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!


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 01: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 09:51 AM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.