Link to home
Start Free TrialLog in
Avatar of NAEDI2
NAEDI2Flag for United States of America

asked on

Xpath expression help

I am just learning Xpath and I hope this is possible.

I have this XML input and need to write the same output while populating the HL_734 with the value of it's 'parent' group in the hierarchy.  The Items levels belong to the preceding Tare level and the Tare levels belong to the preceding Shipment. I hope my diagram makes it clear.

So to read the preceding HL_628 when I come to the next HL_734 it seems that the 'preceding' axis is made for this.  But no matter my syntax I get the '1' in all of my HL_734's or I get nothing.   I have several hundred pages of reference materials but hoped someone could point me in the right direction since I am making no progress.

            <xsl:element name="HL_734">
               <xsl:value-of select="preceding::*/HL_628 [last()]"/>
            </xsl:element>

 

<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<ACTIS>
   <SG0>
      <G_SG0>
         <S_DTM_1_300/>
         <G_HL>
            <S_HL>
               <idHL>HL</idHL>
               <HL_628>1</HL_628>
               <HL_734/>                                    <- Shipment level has no parent
               <HL_735>S</HL_735>
               <HL_736/>
            </S_HL>
            <S_REF_2_1900/>
            <S_DTM_2_3500/>
         </G_HL>
         <G_HL>
            <S_HL>
               <idHL>HL</idHL>
               <HL_628>2</HL_628>
               <HL_734/>                        <- This needs to be populated from the Shipment HL_628 above with value '1'
               <HL_735>T</HL_735>            <- Tare level
               <HL_736/>
            </S_HL>
         </G_HL>
         <G_HL>
            <S_HL>
               <idHL>HL</idHL>
               <HL_628>3</HL_628>
               <HL_734/>                        <- This needs to be populated from the Tare HL_628 above with value '2'
               <HL_735>I</HL_735>            <- Item level
               <HL_736/>
            </S_HL>
         </G_HL>
         <G_HL>
            <S_HL>
               <idHL>HL</idHL>
               <HL_628>4</HL_628>
               <HL_734/>                        <- This needs to be populated from the Tare HL_628 above with value '2'
               <HL_735>I</HL_735>            <- Item level
               <HL_736/>
            </S_HL>
         </G_HL>
SOLUTION
Avatar of Gertone (Geert Bormans)
Gertone (Geert Bormans)
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
It is a best practice to deal with conditionals in predicates in the matches as opposed to big complex xsl:choose
Avatar of NAEDI2

ASKER

I like the approach with the complex predicates.  That's the syntax I am having trouble with and I cant find a good reference book with examples as complex as yours.  But I do get these errors when I run it and I am hoping it's just a simple typo.  I am using Saxon 8.9.

Static error at xsl:element on line 17 column 59 of desadv_x12_856_4010_hl2.desa
dv_x12_856_4010_hl2.xslt.xsl:
  XTDE0820: Element name {S_HL[HL_735 = 'I']/HL_734} is not a valid QName
Syntax error at char 27 in {ancestor::G_HL/preceding::*G_H...} in expression in
xsl:value-of/@select on line 19 column 97 of desadv_x12_856_4010_hl2.desadv_x12_
856_4010_hl2.xslt.xsl:
  XPST0003: Unexpected token name "G_HL" beyond end of expression
Static error at xsl:element on line 23 column 59 of desadv_x12_856_4010_hl2.desa
dv_x12_856_4010_hl2.xslt.xsl:
  XTDE0820: Element name {S_HL[HL_735 = 'T']/HL_734} is not a valid QName
Syntax error at char 27 in {ancestor::G_HL/preceding::*G_H...} in expression in
xsl:value-of/@select on line 25 column 97 of desadv_x12_856_4010_hl2.desadv_x12_
856_4010_hl2.xslt.xsl:
  XPST0003: Unexpected token name "G_HL" beyond end of expression
Static error at xsl:element on line 29 column 59 of desadv_x12_856_4010_hl2.desa
dv_x12_856_4010_hl2.xslt.xsl:
  XTDE0820: Element name {S_HL[HL_735 = 'S']/HL_734} is not a valid QName
Errors were reported during stylesheet compilation
phone typing :-(

   <xsl:template match="S_HL[HL_735 = 'I']/HL_734">
        <xsl:copy>
            <xsl:value-of select="ancestor::G_HL/preceding::G_HL[S_HL/HL_628 = '2'][1]"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="S_HL[HL_735 = 'T']/HL_734">
        <xsl:copy>
            <xsl:value-of select="ancestor::G_HL/preceding::G_HL[S_HL/HL_628 = '1'][1]"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="S_HL[HL_735 = 'S']/HL_734">
        <xsl:copy>
        </xsl:copy>
    </xsl:template>

Open in new window

hang on, I assumed the XML on top is the source you start from
not sure I am copying th eright fields in
can you post source and expected result?
Avatar of NAEDI2

ASKER

My code is working now  thanks to your advice.  I restructured the whole sheet and wound up modifying some of your code to give me the results below.  One thing I could not resolve in the XPath directly was getting the HL_628 from the most recent preceding S_HL group.  I tried [last()] as a predicate but I would always get the value from the very first S_HL group.  I added code to see the number of nodes returned from "preceding::S_HL [HL_735 = 'P']/HL_628" and I got what I expected.  The first node was the first S_HL in the source and  the last was the one I wanted.  The position test works fine but I assume I should be able to do the same with the right XPath?

<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet version="1.0" xmlns:dbg="http://www.ora.com/XSLTCookbook/ns/debug" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:XmlTransform="java:de.axway.converter.xml.xsltextensions.XsltExtensions" exclude-result-prefixes="XmlTransform">
   <xsl:output method="xml" indent="yes" encoding="UTF-8"/>
   <xsl:include href="xtrace.xslt"/>

   <xsl:template match="ACTIS">
      <xsl:call-template name="mainloop"/>
   </xsl:template>

   <xsl:template name="mainloop">
      <xsl:choose>
         <!--  recursive call to step through nodes until reaching the last node without children-->
         <xsl:when test="name(child::*) != ''">
            <xsl:element name="{name()}">
               <xsl:for-each select="child::*">
                  <xsl:call-template name="mainloop"/>
               </xsl:for-each>
            </xsl:element>
         </xsl:when>
         <!--  We reach a node without children so output the elements-->
         <xsl:otherwise>
            <xsl:choose>
               <!--  TYhe one element we will modify is HL-734 -->
               <xsl:when test="name()='HL_734'">
                  <xsl:apply-templates select="current()"/>
               </xsl:when>
               <xsl:otherwise>
                  <!-- Just write the element into results -->
                  <xsl:call-template name="dbg:trace"/>
                  <xsl:element name="{name()}">
                     <xsl:value-of select="."/>
                  </xsl:element>
               </xsl:otherwise>
            </xsl:choose>
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>

   <xsl:template match="S_HL[HL_735 = 'I']/HL_734">  <!--  If we are on an Item level HL -->
      <xsl:call-template name="dbg:trace"/>
      <xsl:for-each select="preceding::S_HL [HL_735 = 'P']/HL_628">  <!-- Pull the HL_628 from the last PACK HL -->
         <xsl:choose>
            <xsl:when test="position()=last()">
               <xsl:element name="HL_734">
                  <xsl:value-of select="."/>
               </xsl:element>
            </xsl:when>
         </xsl:choose>
      </xsl:for-each>
   </xsl:template>

   <xsl:template match="S_HL[HL_735 = 'P']/HL_734">   <!--  If we are on an Pack level HL -->
      <xsl:call-template name="dbg:trace"/>
      <xsl:for-each select="preceding::S_HL [HL_735 = 'T']/HL_628">  <!-- Pull the HL_628 from the last TARE HL -->
         <xsl:choose>
            <xsl:when test="position()=last()">
               <xsl:element name="HL_734">
                  <xsl:value-of select="."/>
               </xsl:element>
            </xsl:when>
         </xsl:choose>
      </xsl:for-each>
   </xsl:template>

   <xsl:template match="S_HL[HL_735 = 'T']/HL_734">   <!--  If we are on an Tare level HL -->
      <xsl:call-template name="dbg:trace"/>
      <xsl:for-each select="preceding::S_HL [HL_735 = 'O']/HL_628">  <!-- Pull the HL_628 from the last ORDER HL -->
         <xsl:choose>
            <xsl:when test="position()=last()">
               <xsl:element name="HL_734">
                  <xsl:value-of select="."/>
               </xsl:element>
            </xsl:when>
         </xsl:choose>
      </xsl:for-each>
   </xsl:template>

   <xsl:template match="S_HL[HL_735 = 'O']/HL_734">   <!--  If we are on an Order level HL -->
      <xsl:call-template name="dbg:trace"/>
      <xsl:for-each select="preceding::S_HL [HL_735 = 'E']/HL_628">  <!-- Pull the HL_628 from the last EQUIPMENT HL -->
         <xsl:choose>
            <xsl:when test="position()=last()">
               <xsl:element name="HL_734">
                  <xsl:value-of select="."/>
               </xsl:element>
            </xsl:when>
         </xsl:choose>
      </xsl:for-each>
   </xsl:template>

   <xsl:template match="S_HL[HL_735 = 'E']/HL_734">   <!--  If we are on an Equipment level HL -->
      <xsl:call-template name="dbg:trace"/>
      <xsl:for-each select="preceding::S_HL [HL_735 = 'S']/HL_628">  <!-- Pull the HL_628 from the last SHIPMENT HL -->
         <xsl:choose>
            <xsl:when test="position()=last()">
               <xsl:element name="HL_734">
                  <xsl:value-of select="."/>
               </xsl:element>
            </xsl:when>
         </xsl:choose>
      </xsl:for-each>
   </xsl:template>

</xsl:stylesheet>
Avatar of NAEDI2

ASKER

Building complex Xpath expressions is especially difficult since all the reference books I can find have limited examples of syntax that combine multiple predicates.  Not only did Geert give my the syntax for my specific needs, but some great general advice wound up being even more helpful.