Querying XML: Use Cases - Use case PARTS: recursive parts explosion. (Page 3 of 5 )
This use case illustrates how a recursive query might can construct a hierarchical document of arbitrary depth from flat structures stored in a database.
This use case is based on a “parts explosion” database that contains information about how parts are used in other parts.
The input to the use case is a “flat” document in which each different part is represented by a
<part>element with
partidand name attributes. Each part may or may not be part of a larger part; if so, the
partidof the larger part is contained in a
partof attribute. This input document might be derived from a relational
database in which each part is represented by a table row with
partidas primary key and
partofas a foreign key referencing
partid.
The challenge of this use case is to write a query that converts the “flat” representation of the parts explosion, based on foreign keys, into a hierarchical representation in which part containment is represented by the document structure.
The input data set uses the following DTD:
<!DOCTYPE partlist[
<!ELEMENT partlist (part*)>
<!ELEMENT part EMPTY>
<!ATTLIST part
partid CDATA #REQUIRED
partof CDATA #IMPLIED
name CDATA #REQUIRED>
]>
Although the
partidand
partofattributes could have been of type ID and IDREF, respectively, in this schema they are treated as character data, possibly materialized in a straightforward way from a relational database. Each
partofattribute matches exactly one
partid. Parts having no
partofattribute are not contained in any other part.
The output data conforms to the following DTD:
<!DOCTYPE parttree [
<!ELEMENT parttree (part*)>
<!ELEMENT part (part*)>
<!ATTLIST part
partid CDATA #REQUIRED
name CDATA #REQUIRED>
]>
Sample data conforming to that DTD might look like this:
<?xml version="1.0" encoding="ISO-8859-1"?>
<partlist>
<part partid="0" name="car"/>
<part partid="1" partof="0" name="engine"/>
<part partid="2" partof="0" name="door"/>
<part partid="3" partof="1" name="piston"/>
<part partid="4" partof="2" name="window"/>
<part partid="5" partof="2" name="lock"/>
<part partid="10" name="skateboard"/>
<part partid="11" partof="10" name="board"/>
<part partid="12" partof="10" name="wheel"/>
<part partid="20" name="canoe"/>
</partlist>
Question 1. Convert the sample document from "partlist" to "parttree" format (see
the DTD section for definitions). In the result document, part containment is
represented by containment of one <part> element inside another. Each part that
is not part of any other part should appear as a separate top-level element in
the output document:
<xsl:template match="partlist">
<parttree>
<!-- Start with the part that is not part of anything -->
<xsl:apply-templates select="part[not(@partof)]"/>
</parttree>
</xsl:template>
<xsl:template match="part">
<part partid="{@partid}" name="{@name}">
<xsl:apply-templates select="../part[@partof = current()/@partid]"/>
</part>
</xsl:template>
It turns out that this sort of transformation is easier to code and understand in
XSLT than in XQuery. For comparison, here is the XQuery solution offered by the
W3C paper:
define function one_level (element $p) returns element
{
<part partid="{ $p/@partid }"
name="{ $p/@name }" >
{
for $s in document("partlist.xml")//part
where $s/@partof = $p/@partid
return one_level($s)
}
</part>
}
<parttree>
{
for $p in document("partlist.xml")//part[empty(@partof)]
return one_level($p)
}
</parttree> Even without a detailed understanding of XQuery, you should be able to see that the XQuery solution is needed to explicitly implement the recursion while XSLT’sapply-templatesand pattern matching allow a more declarative solution. Granted, the difference is not that dramatic, but I find XSLT more elegant for this type of problem.
Next: Use case REF: queries based on references. >>
More XML Tutorials Articles
More By O'Reilly Media
|
This article is excerpted from chapter nine of the XSLT Cookbook, Second Edition, written by Sal Mangano (O'Reilly; ISBN: 0596009747). Copyright © 2007 O'Reilly Media, Inc. Check it out today at your favorite bookstore. Buy this book now.
|
|