Accessing another element in XML

I am trying to create an XML document structure for my application.

I want to keep a list of holes as shown below.

<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 identifier. eg.

 <Drill useHoleWithId='1'/> 

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

Of course, I can find the <Hole> element with an id equal to the value of 'useHoleWithId' and then get the attribute values, but I thought maybe there is a better way to do this using some kind of XML trick. There is?

PS - Although I have no idea about them, maybe any XPath, XLink, XQuery or XPointer could help.

+4
source share
4 answers

XPath is definitely one way to do this. An Xpath query to search for a trend with identifier 1 will look like Holes/Hole[@id="1"]

+4
source

There is a standard XPath function for referencing elements by the id attribute .

From XPath 1.0 spec .:

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

  • id("foo") selects an element with a unique ID foo

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

Another, more general way to access nodes (not just elements) is possible in XSLT . The <xsl:key/> command and XSLT key() specifically designed for this purpose.

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

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

Then in the stylesheet, you can 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> 

Note that keys in XSLT overcome the following limitations of the id() function:

  • Attribute identifiers must be declared as such as DTDs. If an identifier attribute is declared only as an identifier attribute in an external DTD subset, then this will be recognized as an identifier attribute only if the XML processor reads the external DTD set. However, XML does not require XML processors to read an external DTD, and they may not select this, especially if the document is declared standalone="yes" .

  • A document can contain only one set of unique identifiers. There cannot be separate independent sets of unique Identifiers.

  • The identifier of the element can only be specified in the attribute; it cannot be indicated in the content of an element or child.

  • The identifier is limited to the XML interface name. For example, it cannot contain space.

  • An element can have no more than one identifier.

  • No more than one element can have a specific identifier.

Due to these limitations, XML documents sometimes contain a cross-reference structure that is not explicitly declared by the ID / IDREF / IDREFS attributes.

+3
source

XML is an inert view of data. You have already created your link using "useHoleWithId". How you interpret and act on this to get this <hole> element before your implementation, and of course, xpath (xslt to change the document just implements xpath for this) is a powerful way to do this.

+1
source

You can convert 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> 

to make the Hole attribute appear in Drill tags

0
source

All Articles