• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 418
  • Last Modified:

XSL Tree for-each

I am looking to build a tree from a bill of material using XSL. I able to get each individual level, but do not know how to do a nested loop to pull it all together. My XML file is formatted as follows (example of 3 levels): If I change the ="*/*" to "*/*/*/*" I get the second level, and if I use "*/*/*/*/*/*" I get level 3.

How do I nest these together to get one indented tree with the children underneath the parent.

:
<SUBPARTS>
<PART>
<ID></ID>
<DESCRIPTION></DESCRIPTION>
<PARENT></PARENT>
</PART>
<PART>
<ID></ID>
<DESCRIPTION></DESCRIPTION>
<PARENT></PARENT>
</PART>

<PART>
<ID></ID>
<DESCRIPTION></DESCRIPTION>
<PARENT></PARENT>
<SUBPARTS>
<PART>
<ID></ID>
<DESCRIPTION></DESCRIPTION>
<PARENT></PARENT>
<SUBPARTS>
<PART>
<ID></ID>
<DESCRIPTION></DESCRIPTION>
<PARENT></PARENT>
</PART>
</SUBPART>
</PART>
</SUBPART>
</PART>
</SUBPART>




<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
>
<xsl:template match="/">
  <html>
  <body>
  <h2>My Parts</h2>
  <table border="1">
    <tr bgcolor="#9acd32">
      <th>ID</th>
      <th>Description</th>
      <th>Parent</th>
    </tr>
    <xsl:for-each select="*/*">
    <tr>
      <td><xsl:value-of select="ID"/></td>
      <td><xsl:value-of
select="Description"/></td>
<td><xsl:value-of select="Parent"/></td>
    </tr>
    </xsl:for-each>
0
phil301
Asked:
phil301
  • 9
  • 7
  • 3
1 Solution
 
abelCommented:
Why did you post in a DB zone? The XSLT zone and XML would've been excellent for this :)

> How do I nest these together to get one indented tree with the children underneath the parent.

not so sure what you mean by this, but templates in XSLT are the means to work with input data. For-each is sometimes a convenience, but not when you need to loop through several levels. Hold on, I'll give an example.
0
 
Geert BormansInformation ArchitectCommented:
In order to achieve this, you should use apply-templates and seperate templates instead of for-each
I have two questions
- could it be that you have a missbalanced XML and that the closing tag for <SUBPARTS> is wrongly </SUBPART>?
- can you please post data with some content in it and the result you want?

cheers

Geert
0
 
abelCommented:
hmm, your data is not complete. Can you paste a valid piece of XML so that I can be sure that I work on the input you want me to work on?
0
Cloud Class® Course: C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

 
Geert BormansInformation ArchitectCommented:
I twiddled a bit with your data, I think this is what you need.
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    >
    <xsl:template match="/">
        <html>
            <body>
                <h2>My Parts</h2>
                <table border="1">
                    <tr bgcolor="#9acd32">
                        <th>ID</th>
                        <th>Description</th>
                        <th>Parent</th>
                    </tr>
                    <xsl:apply-templates select="SUBPART/PART"></xsl:apply-templates>
                </table>
            </body>
        </html>
    </xsl:template>
    
    <xsl:template match="PART">
        <tr>
            <td><xsl:value-of select="ID"/></td>
            <td><xsl:value-of 
                select="DESCRIPTION"/></td>
            <td>
                <xsl:choose>
                    <xsl:when test="ancestor::PART">
                        <xsl:value-of select="ancestor::PART[1]/ID"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>TOP</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
            </td>
        </tr>
        <xsl:apply-templates select="SUBPART/PART"></xsl:apply-templates>
    </xsl:template>
    
</xsl:stylesheet>

Open in new window

0
 
Geert BormansInformation ArchitectCommented:
This is the data I used,

Note in the XSLT that I push out the selected nodes (SUBPART/PART)
to the relevant template, which is the PART template,
and after creating the row, I continu doing this nested work with the possible SUBPART/PART children

This is how you do hierarchical processing in XSLT
Doing this with for-each, will result in very deeply nested code, and that is hardly maintainable
<?xml version="1.0" encoding="UTF-8"?>
<SUBPART>
    <PART>
        <ID>A</ID>
        <DESCRIPTION>FOO-A</DESCRIPTION>
    </PART>
    <PART>
        <ID>B</ID>
        <DESCRIPTION>FOO-B</DESCRIPTION>
    </PART>
    <PART>
        <ID>C</ID>
        <DESCRIPTION>FOO-C</DESCRIPTION>
        <SUBPART>
            <PART>
                <ID>D</ID>
                <DESCRIPTION>FOO-D</DESCRIPTION>
                <SUBPART>
                    <PART>
                        <ID>E</ID>
                        <DESCRIPTION>FOO-E</DESCRIPTION>
                    </PART>
                </SUBPART>
            </PART>
        </SUBPART>
    </PART>
</SUBPART>

Open in new window

0
 
Geert BormansInformation ArchitectCommented:
Hi abel, I did not see your first post, only your second
seems like your example would have gone in the same direction anyway

@phil, with "I push out the selected nodes", I mean that is what I do with the apply-templates.
You actually select a bunch of nodes and you evaluate them against the match attributes of the different templates
I hope you catch the drift
0
 
phil301Author Commented:
Thanks for the quick replys. I will try this when I get back to the office in the morning.

The actual XML data is confidential data, but I should be able to modify it and post the data.

The XML that Getrone recreated looks correct.

Thanks again for the quick replys, I will get back with you in the morning.
0
 
phil301Author Commented:
By the way, this is my first experience with XML ,
0
 
abelCommented:
> seems like your example would have gone in the same direction anyway

yes, about, but you're quite a bit quicker with coming up with a good example. You never sleep? lol ;-)
0
 
Geert BormansInformation ArchitectCommented:
oh, I slept one hour Sunday afternoon prior to watching a bit of the Amstel Gold Race,
and then, if I remember well, I must have slept an hour or two in January :-)
0
 
phil301Author Commented:
I tried to insert the XSL code above and get the following error:


The XML page cannot be displayed
Cannot view XML input using XSL style sheet. Please correct the error and then click the Refresh button, or try again later.


--------------------------------------------------------------------------------

Invalid at the top level of the document. Error processing resource 'file:///C:/XMLExport/xmlstyle.xslt'. Line 40, Positio...

</xsl:stylesheet>

0
 
Geert BormansInformation ArchitectCommented:
When copying the XSLT from the edit field,
you did not by any chance copy the words
"Open in New Window Select All" after the stylesheet as well,
it happens to me all the time
make sure that the last string in your XSLT is the closing tag for xsl:stylesheet
0
 
phil301Author Commented:
Ok, getting closer. Not sure what the problem above was.
I am able to run it now, but I am still only getting top level parts, and an extra column on the right that has the text "Top" in it.
0
 
phil301Author Commented:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
   
here is the XSL I am using now.


xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    >
    <xsl:template match="/">
        <html>
            <body>
                <h2>My Parts</h2>
                <table border="1">
                    <tr bgcolor="#9acd32">
                        <th>ID</th>
                        <th>Description</th>
                        <th>Parent</th>
                    </tr>
                    <xsl:apply-templates

select="SUBPARTS/PART"></xsl:apply-templates>
                </table>
            </body>
        </html>
    </xsl:template>
   
    <xsl:template match="PART">
        <tr>
            <td><xsl:value-of select="ID"/></td>
            <td><xsl:value-of
                select="Description"/></td>
           
          <td><xsl:value-of
                select="Parent"/></td>
            <td>
                <xsl:choose>
                    <xsl:when

test="ancestor::PART">
                        <xsl:value-of

select="ancestor::PART[1]/ID"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:text>TOP</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
            </td>
        </tr>
        <xsl:apply-templates

select="SUBPART/PART"></xsl:apply-templates>
    </xsl:template>
   
</xsl:stylesheet>
0
 
Geert BormansInformation ArchitectCommented:
Try first with my example XML
Then see what is different
Preferably, take a part from your real XML and twiddle a bit with the data
If you wish, I can send you an XSLT that leaves the structure intact, but changes every character in a *
0
 
phil301Author Commented:
Here is the actual XML with data X'ed out

<?xml version="1.0" encoding="ISO-8859-1"?>
<?xml-stylesheet type="text/xsl" href="xmlstyle.xslt"?>
<SUBPARTS>
      <PART>
            <ID>XXXXXXX</ID>
            <Description>XXXXXXX</Description>
            <Drawing>XXXXXXX</Drawing>
            <Parent>XXXXXXX</Parent>
            <Qty>X</Qty>
            <NSN>XXXXXXX</NSN>
      <\PART>
      <PART>
            <ID>XXXXXXX</ID>
            <Description>XXXXXXX</Description>
            <Drawing>XXXXXXX</Drawing>
            <Parent>XXXXXXX</Parent>
            <Qty>X</Qty>
            <NSN>XXXXXXX</NSN>
      <\PART>
      <PART>
            <ID>XXXXXXX</ID>
            <Description>XXXXXXX</Description>
            <Drawing>XXXXXXX</Drawing>
            <Parent>XXXXXXX</Parent>
            <Qty>X</Qty>
            <NSN>XXXXXXX</NSN>
                  <SUBPARTS>
                        <PART>
                              <ID>XXXXXXX</ID>
                              <Description>XXXXXXX</Description>
                              <Drawing>XXXXXXX</Drawing>
                              <Parent>XXXXXXX</Parent>
                              <Qty>X</Qty>
                              <NSN>XXXXXXX</NSN>
                        <\PART>
                        <PART>
                              <ID>XXXXXXX</ID>
                              <Description>XXXXXXX</Description>
                              <Drawing>XXXXXXX</Drawing>
                              <Parent>XXXXXXX</Parent>
                              <Qty>X</Qty>
                              <NSN>XXXXXXX</NSN>
                        <\PART>
                  <\SUBPARTS>
      <\PART>
      <PART>
            <ID>XXXXXXX</ID>
            <ID>XXXXXXX</ID>
            <Description>XXXXXXX</Description>
            <Drawing>XXXXXXX</Drawing>
            <Parent>XXXXXXX</Parent>
            <Qty>X</Qty>
            <NSN>XXXXXXX</NSN>
      <\PART>
      <PART>
            <ID>XXXXXXX</ID>
            <Description>XXXXXXX</Description>
            <Drawing>XXXXXXX</Drawing>
            <Parent>XXXXXXX</Parent>
            <Qty>X</Qty>
            <NSN>XXXXXXX</NSN>
      <\PART>
<\SUBPARTS>
0
 
Geert BormansInformation ArchitectCommented:
the problem is close to the end of your stylesheet
there is a SUBPART that should be SUBPARTS
       <xsl:apply-templates 
 
select="SUBPARTS/PART"></xsl:apply-templates>
    </xsl:template>
    
</xsl:stylesheet>

Open in new window

0
 
phil301Author Commented:
You sir are a genius. That works great. I just now have to work on indentation of the children and a way to print it out in the indented structure.



Thank you so much for your help.
0
 
Geert BormansInformation ArchitectCommented:
welcome
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

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.

  • 9
  • 7
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now