3

Beginner's question here:

Given the following XML excerpt:

<root>
  <element>
    <child1>a</child1><child2>b</child2><child3>c</child3>
  </element>
</root>

When I'm at the child3 context, I can use preceding-sibling::* to get the child2 node. All right.

In the following XML excerpt:

<root>
  <element child1="a" child2="b" child3="c">
  </element>
</root>

When I'm at the child3 context, is it right that there is no axis in XPath 1.0 to get the child2 attribute node? I think I'd need something like preceding-sibling-attribute:: that is not available.

As a side question, is this possible with XPath 2?

MazeGen
  • 180
  • 3
  • 14
  • Can you explain your requirement in conceptual terms, besides the example ("getting from child3 to child2")? If the conceptual requirement is "select the previous attribute", then no it's not possible, because the concept is not well-defined in XML. – LarsH Nov 30 '12 at 16:20

1 Answers1

4

It's true that there is no single axis to get from one attribute to another, but of course you can get there by chaining axes.

Attributes are not considered siblings, because they are not considered 'children' of the parent element, in the data model XPath uses. That's one reason why preceding-sibling:: won't work. It also means that attribute names such as child1, child2 etc. are misleading in that attributes are not "children".

The other reason preceding-sibling:: won't work is that the order of attributes of a given element is undefined (implementation-dependent). Attributes must be listed in some order in a given serialization (e.g. in a file), but that file could be parsed and output again with the attributes in a different order, and it would still be considered the same document from an XML info model point of view. Therefore, there is no such thing as the "previous" or "preceding" attribute in XML.

To get the value of the child2 attribute from the context of the child3 attribute, you can use one of these depending on how you know which attribute you want...

../@child2

"The attribute named child2 of the parent element"

../@*[name() != name(current())]

"The other attributes of the parent element (not this one)"

You could even try

../@*[2]

but the results would not be predictable in general, since the order of attributes is undefined.

If the attribute names include an index component (1, 2, 3) as in your example, you could replace the number in name(current()) with a smaller number.

To answer your side question, it depends on how your requirement is defined. If the requirement is "select the previous attribute", then no, that concept is not defined in XPath 2 either.

LarsH
  • 27,481
  • 8
  • 94
  • 152
  • 1
    Thank you for exhaustive answer, LarsH. I generate an XML file and I wanted to transform some attributes to HTML in exactly the same order as they appear in the XML file. The processing is a bit complicated so needed to know if an attribute is the first one. You clarified this by referring to the fact that order of attributes of a given element is undefined. Thanks to the fact I completely own the XML file, I'm going to change the generator so that elements are used instead of attributes. This will solve my issue. – MazeGen Nov 30 '12 at 16:43
  • @Karel: excellent decision. When the order of things in an XML file is significant, you really do need to use elements rather than attributes. – LarsH Nov 30 '12 at 19:20