Solved

How would I display a simple recursive relationship in XSL starting from the node that doesn't have a idref?

Posted on 2009-04-08
14
349 Views
Last Modified: 2013-11-18
          I have an XSD file as a schema and a sample XML file. I am trying to get the XSL to display information about rank or position by following the relationship chain by using the id and the idref in the files. Basically I'm trying to display the information so that the node without a idref will be listed first, and then the node that references the node without a ref will be listed second, and then the node that references the second will be listed third. For example,

<cat>
<name>mellow</name>
<id>c1</id>
</cat>


<cat>
<name>apple</name>
<id>c3<id/>
<idref>c2</idref>
</cat>

<cat>
<name>miles</name>
<id>c2<id/>
<idref>c1</idref>
</cat>


basically I want to display cat c1 first, c2 second, and c3 third by following the id, idref chain.
0
Comment
Question by:AlexanderMaxwell
  • 7
  • 4
  • 2
14 Comments
 
LVL 60

Accepted Solution

by:
Geert Bormans earned 150 total points
Comment Utility
You can use a key to index all the cat elements, based on there idref

I added a cats root element to get started
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:key name="ref" match="cat" use="idref"/>

    <xsl:template match="cats">

        <xsl:apply-templates select="cat[not(idref)]"></xsl:apply-templates>

    </xsl:template>

    <xsl:template match="cat">

        <xsl:value-of select="name"/>

        <xsl:apply-templates select="key('ref', id)"></xsl:apply-templates>

    </xsl:template>

</xsl:stylesheet>

Open in new window

0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
The code starts with the root element and selects in an apply-templates the cat that does not have an idref
in the cat template I call out for the indexed cat element that has the correct idref, using the key function
0
 
LVL 20

Assisted Solution

by:ChristoferDutz
ChristoferDutz earned 100 total points
Comment Utility
Hi

I hope I understood your question right, but I think this Xsl should do the trick:

It iterates over all cat elements with no idref-element and then delegates to the outputCat template to output all elements referencing the current id. When outputing any nodes referencing, the template recursively calls itself to output any cat referencing the currently output cat.

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

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="/">

        <xsl:for-each select="//cat[count(idref) = 0]">

            <xsl:value-of select="name"/>

            <xsl:call-template name="outputCat">

                <xsl:with-param name="context" select="."/>

            </xsl:call-template>

        </xsl:for-each>

    </xsl:template>

    <xsl:template name="outputCat">

        <xsl:param name="context" select="."/>

        <xsl:for-each select="//cat[idref = $context/id]">

            <xsl:value-of select="name"/>

            <xsl:call-template name="outputCat">

                <xsl:with-param name="context" select="."/>

            </xsl:call-template>

        </xsl:for-each>

    </xsl:template>

</xsl:stylesheet>

Open in new window

0
 

Author Comment

by:AlexanderMaxwell
Comment Utility
I realizes I didn't attach my code snippet, thanks for the help so far guys, I'll take a look at them. I'll let you guys see my code, so you can understand what exactly I'm trying to learn.
XSD:
 
 
 

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

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">

    <!--university catalog-->

    <xs:element name="UniversitiesOfNation">

        <xs:complexType>

            <xs:sequence>

               

                <xs:element name = "Region" type = "Regiontype" minOccurs="1" maxOccurs="unbounded"/>

            </xs:sequence>

        </xs:complexType>

    </xs:element>
 

<!--region-->

    <xs:complexType name="Regiontype" >

        <xs:sequence>

            <xs:element name="Country" type="xs:string"/>

            <xs:element name="ISO" type="xs:string"/>

            <xs:element name="Population" type="xs:int"/>

            <xs:element name="PremierUniversity" type="GenAreatype" minOccurs="1" maxOccurs="1"/>

            <xs:element name="GenArea" type="GenAreatype" minOccurs="1" maxOccurs="unbounded"/> 

        </xs:sequence>

    </xs:complexType> 

    

    

    

    <!--state-->

    <xs:complexType name="GenAreatype" >

        <xs:sequence>

        <xs:element name="State" type="xs:string"/>

        <xs:element name="Area" type="Areatype" minOccurs="1" maxOccurs="unbounded"/>

        </xs:sequence>

    </xs:complexType> 

    

    <!--city-->

    <xs:complexType name="Areatype" >

        <xs:sequence>

            <xs:element name="city" type="xs:string"/>

            <xs:element name="university" type="universitytype" minOccurs="1" maxOccurs="unbounded"/>

        </xs:sequence>

    </xs:complexType> 

    

<!--university-->

    

    <!--university-->

    <xs:complexType name="universitytype" >

        <xs:sequence>

            <xs:element name="Name" type="xs:string"/>

            <xs:element name="UniversityID" type="xs:ID" minOccurs="1" maxOccurs="1"/>

            <xs:element name="PrecedingUniversityID" type="xs:IDREF" minOccurs="0" maxOccurs="1"/>

            <xs:element name="Address" type="addresstype" minOccurs="0" maxOccurs="1"/>

            <xs:element name="Department" type="departmenttype" minOccurs="0" maxOccurs="unbounded"/>

        </xs:sequence>

    </xs:complexType>  
 
 

    <!--address-->

    

    <xs:complexType name="addresstype" >

        <xs:sequence> 

            <xs:element name="street" type="xs:string"/>

            <xs:element name="zipcode" type="xs:integer"/>

        </xs:sequence>

    </xs:complexType>

    

    <!--departmenttype-->

    <xs:complexType name="departmenttype" >

        <xs:sequence> 

            <xs:element name="DepartmentName" type="xs:string"/>

        </xs:sequence>

    </xs:complexType>
 

</xs:schema>
 
 
 
 

XML:
 
 

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

<?xml-stylesheet type="text/xsl" href="rank.xsl"?>

<UniversitiesOfNation xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:noNamespaceSchemaLocation="UniversitiesOfCountry.xsd">

    <Region>

        <Country>United States of America</Country>

        <ISO>US</ISO>

        <Population>300000000</Population>

        <PremierUniversity>

             <State>massachusetts</State>

            <Area>

                <city>Cambridge</city>

                <university>         

                    <Name>Harvard</Name>

                    <UniversityID>U1</UniversityID> 

                    

                    <Address>

                        <street>201 Cambridge st</street>

                        <zipcode>12345</zipcode>

                    </Address>

                    <Department>

                        <DepartmentName>INFO</DepartmentName>

                    </Department>

                    

                </university>

            </Area>

        </PremierUniversity>

        <GenArea>

            <State>GA</State>

            <Area>

                <city>Macon</city>

                <university>

                    

                    <Name>Macon State University</Name>

                    <UniversityID>U2</UniversityID>

                    <PrecedingUniversityID>U1</PrecedingUniversityID>

                    <Address>

                        <street>2234 Hope Street</street>

                        <zipcode>31078</zipcode>

                    </Address>

                    <Department>

                        <DepartmentName>Maps</DepartmentName>

                    </Department>

                    <Department>

                        <DepartmentName>MIS</DepartmentName>

                    </Department>

                    

                    

                </university>

                <university>

                   

                    <Name>Wesleyn</Name>

                    

                    

                    <UniversityID>U4</UniversityID>

                    <PrecedingUniversityID>U3</PrecedingUniversityID>

                    <Address>

                        <street>55 Street Street</street>

                        <zipcode>31078</zipcode>

                    </Address>

                    <Department>

                        <DepartmentName>MIS</DepartmentName>

                       

                    </Department>

                    

                </university> 

                <university>

                 

                    <Name>Mercer</Name>

                    <UniversityID>U3</UniversityID>

                    <PrecedingUniversityID>U2</PrecedingUniversityID>

                    <Address>

                        <street>200 Baldwin Street</street>

                        <zipcode>31078</zipcode>

                    </Address>

                </university> 

            </Area>

            <Area>

                <city>Valdosta</city>

                <university>

               

                    <Name>Valdosta University</Name>

                    <UniversityID>U5</UniversityID>

                    <PrecedingUniversityID>U4</PrecedingUniversityID>

                    <Address>

                        <street>333 hame Street</street>

                        <zipcode>11234</zipcode>

                    </Address>

                </university>

                <university>

                    <Name>HAVOC University</Name>

                    <UniversityID>U6</UniversityID>

                    <PrecedingUniversityID>U5</PrecedingUniversityID>

                    <Address>

                        <street>123 Ny Street</street>

                        <zipcode>44534</zipcode>

                    </Address>

                </university>

            </Area>

        </GenArea>

    </Region>

    <Region>

        <Country>China</Country>

        <ISO>CN</ISO>

        <Population>1500000000</Population>

        <PremierUniversity>

            <State>none</State>

            <Area>

                <city>Hong Kong</city>

                <university>

                    <Name>University of China</Name>

                    <UniversityID>U7</UniversityID>

                    <PrecedingUniversityID>U6</PrecedingUniversityID>

                    <Address>

                        <street>Beijing st</street>

                        <zipcode>54321</zipcode>

                    </Address>

                    <Department>

                        <DepartmentName>MIS</DepartmentName>

                    </Department>

                </university>

            </Area>

        </PremierUniversity>

        <GenArea>

            <State>none</State>

            <Area>

                <city>Beijing</city>

                <university>

                    <Name>Beijing Univeristy</Name>

                    <UniversityID>U8</UniversityID>

                    <PrecedingUniversityID>U7</PrecedingUniversityID>

                    <Address>

                        <street>21058 Japan st</street>

                        <zipcode>22331</zipcode>

                    </Address>

                </university>

            </Area>

        </GenArea>

    </Region>

    

</UniversitiesOfNation>

Open in new window

0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
@ChristopherDutz,

If you allow me, I have some suggestions for your stylesheet,
I hope you appreciate the suggestions

1. <xsl:for-each select="//cat[count(idref) = 0]">
It is considered good XSLT design to avoid for-each in this kind of situations.
for-each will cause a certain nesting in your programming code, which will make your code highly unmaintainable in the end
this nesting can be avoide by using apply-templates and seperate templates

2. <xsl:for-each select="//cat[idref = $context/id]">
This is a real performance killer
with // you are traversing the entire document tree looking for elements
This is a very small XML set, but that still is no reason to not apply good practice
Not using "//cat" but using "/cats/cat" would improve performance a lot
Using keys, as I did in my proposed solution is the real way to go

3. There is no need for making a named template.
Building recursion using named templates usually is a good thing, if you are not simply jumping element nodes as in this example.
XSLT processors are optimised for dealing with apply-template processing
Not every XSLT processor has the same optimisation for recursive named template processing... so there might be too much information stored on the stack

4. a smaller issue
<xsl:for-each select="//cat[count(idref) = 0]">
would be better done by not counting but using the default boolean
<xsl:for-each select="//cat[not(idref)]">

Hope you like this and learn from this.
I am sure you would benefit from reviewing my proposed solution

cheers

Geert
0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
@AlexanderMaxwell,
I am sorry but I don't understand why you accept ChristopherDutz' answer.
1. It was not the first correct answer given.
2. Mine is superior over the other
Policy of EE is that you accept the first correct answer or split points
I don't care for the points but
1. Now others that find this answer in the database will learn the wrong things, and things are severely wrong as you can see from my follow up
2. I am working for this years "sniper" (answers hit performance), so this question is really bad for my statistics.
I would appreciate that you reopen the question and accept the right answer,
thanks for that
0
Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

 
LVL 20

Expert Comment

by:ChristoferDutz
Comment Utility
I have to admit, that I liked the other solution much better too :-) So go ahead :-)
0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
My code, applied to your XML,
creating an HTML table of universities
<?xml version="1.0" encoding="UTF-8"?>

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:key name="ref" match="university" use="PrecedingUniversityID"/>

    <xsl:template match="/">

        <table border="1">

            <xsl:apply-templates select="//university[not(PrecedingUniversityID)]"></xsl:apply-templates>

            

        </table>

    </xsl:template>

    <xsl:template match="university">

        <tr>

            <td><xsl:value-of select="UniversityID"/></td>

            <td><xsl:value-of select="PrecedingUniversityID"/></td>

            <td><xsl:value-of select="Name"/></td>

            <td><xsl:value-of select="ancestor::Area/city"/></td>

        </tr>

        <xsl:value-of select="name"/>

        <xsl:apply-templates select="key('ref', UniversityID)"></xsl:apply-templates>

    </xsl:template>

</xsl:stylesheet>

Open in new window

0
 

Author Comment

by:AlexanderMaxwell
Comment Utility
I'm sorry Gertrone, I'm still examining the answers given. However, for my problem, the given solution seemed to work. I'm new here so I guess I didn't wait long enough before evaluating. In the future I will be more careful.

Thanks,

Alexander
0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
well, pay attention to my comments on the accepted solution, I hope you learn from them... a lot of good tips in there
0
 

Author Comment

by:AlexanderMaxwell
Comment Utility
No offenses to ChristoferDutz, but I would reopen the question, but I don't know how. I'm still pretty new.
0
 
LVL 60

Expert Comment

by:Geert Bormans
Comment Utility
There is a link in the original question
"Request Attention"
Click it and describe what you want to do.
It will then be posted to community support

I suggest that you ask for a split points (after all, Christopher gave a working solution too)
I don't care how much points I get exactly in the split,
after a split, both solutions wil be highlighted if someone hits this question searching the EE database,
I am happy as long as attention is drawn to the correct solution too

0
 

Author Closing Comment

by:AlexanderMaxwell
Comment Utility
Thanks, this worked fine. I'm a beginner so I can't quite tell what's going on, but I think I can follow it.
0

Featured Post

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Styling your websites can become very complex. Here I'll show how SASS can help you better organize, maintain and reuse your CSS code.
JavaScript has plenty of pieces of code people often just copy/paste from somewhere but never quite fully understand. Self-Executing functions are just one good example that I'll try to demystify here.
Viewers will learn about basic arrays, how to declare them, and how to use them. Introduction and definition: Declare an array and cover the syntax of declaring them: Initialize every index in the created array: Example/Features of a basic arr…
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.

763 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

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now