tags:

views:

521

answers:

4

I'm trying to design an XML document structure for my application. I want to store a list of holes like following

<Holes>
 <Hole id='1' dia='0.1' depth='2'/>
 <Hole id='2' dia='0.2' depth='1.67'/>
 <Hole id='3' dia='0.3' depth='0.44'/>
</Holes>

In another part of my document I want to refer to a hole by its id. e.g.

<Drill useHoleWithId='1'/>

When my code finds above <Drill> element I want it to retrieve the values of 'dia' and 'depth' attributes in the <Hole> element that has id='1'.

Of course I can search for a <Hole> element with id equal to the value of 'useHoleWithId' and then get the values of the attributes, but I thought maybe there's a better way to do this using some XML trick. Is there?

PS - Though I don't have any idea about them, may be any of XPath, XLink, XQuery or XPointer could help.

+4  A: 

XPath is certainly one way to do it. An Xpath query to find the hold with id 1 would be something like Holes/Hole[@id="1"]

Paul Dixon
A: 

You may transform it:

  <xsl:for-each select="my/Drill">
   <xsl:variable name="drillid"> 
    <xsl:value-of select="@useHoleWithId"/>
   </xsl:variable> 
   <Drill>
    <xsl:attribute name="diameter">
     <xsl:value-of select="/my/Holes/Hole[@id=$drillid]/@dia"/>
    </xsl:attribute>
    <xsl:attribute name="useid">
     <xsl:value-of select="$drillid"/>
    </xsl:attribute>
   </Drill>
  </xsl:for-each>

so that Hole's attribute will appear in Drill tags

Quassnoi
+1  A: 

XML is an inert view on the data. You already have created your reference with "useHoleWithId". How you interpret and act upon that to get that <hole> element is up to your implementation, and certainly xpath (xslt to change the document is just implementing xpath to do this) is a strong way to do this.

annakata
+2  A: 

There is a standard XPath function to reference elements by their "id" attribute.

From the XPath 1.0 spec.:

The id() function function selects elements by their unique ID (see [5.2.1 Unique IDs]). When the argument to id is of type node-set, then the result is the union of the result of applying id to the string-value of each of the nodes in the argument node-set. When the argument to id is of any other type, the argument is converted to a string as if by a call to the string function; the string is split into a whitespace-separated list of tokens (whitespace is any sequence of characters matching the production S); the result is a node-set containing the elements in the same document as the context node that have a unique ID equal to any of the tokens in the list.

  • id("foo") selects the element with unique ID foo

  • id("foo")/child::para[position()=5] selects the fifth para child of the
    element with unique ID foo

Another, more generic way of referring to nodes (not only elements) is possible in XSLT. The <xsl:key/> instruction and the XSLT key() function are specifically designed for this purpose.

For example, suppose a document contains bibliographic references in the form XSLT, and there is a separate XML document bib.xml containing a bibliographic database with entries in the form:

<entry name="XSLT">...</entry>

Then the stylesheet could use the following to transform the bibref elements:

<xsl:key name="bib" match="entry" use="@name"/>

<xsl:template match="bibref">
  <xsl:variable name="name" select="."/>
  <xsl:for-each select="document('bib.xml')">
    <xsl:apply-templates select="key('bib',$name)"/>
  </xsl:for-each>
</xsl:template>

Do note, that keys in XSLT overcome the following limitations of the id() function:

  • ID attributes must be declared as such in the DTD. If an ID attribute is declared as an ID attribute only in the external DTD subset, then it will be recognized as an ID attribute only if the XML processor reads the external DTD subset. However, XML does not require XML processors to read the external DTD, and they may well choose not to do so, especially if the document is declared standalone="yes".

  • A document can contain only a single set of unique IDs. There cannot be separate independent sets of unique IDs.

  • The ID of an element can only be specified in an attribute; it cannot be specified by the content of the element, or by a child element.

  • An ID is constrained to be an XML name. For example, it cannot contain spaces.

  • An element can have at most one ID.

  • At most one element can have a particular ID.

Because of these limitations XML documents sometimes contain a cross-reference structure that is not explicitly declared by ID/IDREF/IDREFS attributes.

Dimitre Novatchev