Re: [xsl] Navigating XML Using Attributes

Subject: Re: [xsl] Navigating XML Using Attributes
From: Wendell Piez <wapiez@xxxxxxxxxxxxxxxx>
Date: Tue, 11 Feb 2003 17:57:23 -0500
James,

You can do it without, but keys were invented just for this purpose. Look them up: they're described in the XSLT spec or in any decent book or web resource on XSLT.

In your case, the fact that you're using elements of exactly the same name and attribute name to refer to the target elements you want, you need to be careful in constructing your key. For example, if you declare a key like this:

<xsl:key name="elements-by-id" match="*" use="@Id"/>

And then, when processing the LevelA3 Id="111" element under the LevelA2 parent, you call

<xsl:apply-templates select="key('elements-by-id', @Id)"/>

you would process all elements with @Id="111", including the context node itself (thereby entering an infinite loop).

But if you declare the key as

<xsl:key name="top-level-by-id" match="Account/*" use="@Id"/>

the same expression will return only the <LevelA3 Id="111"> child of <Account> -- since the other one (the context node) doesn't match the pattern used in the key declaration.

I hope this is enough to get you moving. You can either declare one key for all your elements, or separate keys for your separate types. Either way they can be chained as you describe.

Good luck,
Wendell

At 04:42 PM 2/11/2003, you wrote:
I have an XML document that was dumped from a database. Instead of the elements being nested in an appropriate, well-formed XML fashion, they are associated with ID attributes. The following XML is a generalized sample with Account being the root element:

<?xml version="1.0" encoding="UTF-8"?>
<Account>
        <LevelA1>
                <LevelA2>
                        <LevelA3 Id="111"/>
                        <LevelA3 Id="222"/>
                        <LevelA3 Id="333"/>
                </LevelA2>
        </LevelA1>
        <LevelA3 Id="111">
                <LevelB1>
                        <LevelB2 Id="1"/>
                        <LevelB2 Id="2"/>
                        <LevelB2 Id="3"/>
                        <LevelB2 Id="4"/>
                </LevelB1>
        </LevelA3>
        <LevelB2 Id="1">
                <LevelC1>data</LevelC1>
        </LevelB2>
        <LevelB2 Id="2">
                <LevelC1>data</LevelC1>
        </LevelB2>
        <LevelB2 Id="3">
                <LevelC1>data</LevelC1>
        </LevelB2>
        <LevelB2 Id="4">
                <LevelC1>data</LevelC1>
        </LevelB2>
        <LevelA3 Id="222">
                <LevelB1>
                        <LevelB2 Id="5"/>
                        <LevelB2 Id="6"/>
                        <LevelB2 Id="7"/>
                        <LevelB2 Id="8"/>
                </LevelB1>
        </LevelA3>
        <LevelB2 Id="5">
                <LevelC1>data</LevelC1>
        </LevelB2>
        <LevelB2 Id="6">
                <LevelC1>data</LevelC1>
        </LevelB2>
        <LevelB2 Id="7">
                <LevelC1>data</LevelC1>
        </LevelB2>
        <LevelB2 Id="8">
                <LevelC1>data</LevelC1>
        </LevelB2>
        <LevelA3 Id="333">
                <LevelB1>
                        <LevelB2 Id="9"/>
                        <LevelB2 Id="10"/>
                        <LevelB2 Id="11"/>
                        <LevelB2 Id="12"/>
                </LevelB1>
        </LevelA3>
        <LevelB2 Id="9">
                <LevelC1>DataAlpha</LevelC1>
        </LevelB2>
        <LevelB2 Id="10">
                <LevelC1>DataBeta</LevelC1>
        </LevelB2>
        <LevelB2 Id="11">
                <LevelC1>DataGamma</LevelC1>
        </LevelB2>
        <LevelB2 Id="12">
                <LevelC1>DataDelta</LevelC1>
        </LevelB2>
</Account>

To navigate the XML document, one must pull the Ids from element <LevelA3> and return to the <Account> level to find the <LevelA3> elements that reside in the document just below <Account>. Once the appropriate <LevelA3> element is found, the XSL must find its way to <LevelB2>, grab its Id, return to the top and find <LevelB2> below. This continues until the data contained in <LevelC1> is found. For example, the path to DataGamma is:
Account/LevelA1/LevelA2/LevelA3 Id="333"/LevelB1/LevelB2 Id="11"/LevelC1:DataGamma


I assume I will have to use apply-templates again and again. What I don't know is how to remember all the Ids in LevelA3, and below, so I can find each of the cooresponding elements. Any suggestions?


======================================================================
Wendell Piez                            mailto:wapiez@xxxxxxxxxxxxxxxx
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
  Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================


XSL-List info and archive: http://www.mulberrytech.com/xsl/xsl-list



Current Thread