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(_at_)mulberrytech(_dot_)com
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