这些属性之所以特殊是因为它们的类型,而不是因为它们的名称。
XML 中的 ID
虽然很容易将属性视为name="value",其值是一个简单的字符串,但这并不是全部——还有一个与属性相关的属性类型。
当涉及到 XML Schema 时,这很容易理解,因为 XML Schema 支持 XML 元素和 XML 属性的数据类型。 XML 属性被定义为简单类型(例如 xs:string、xs:integer、xs:dateTime、xs:anyURI)。这里讨论的属性是使用xs:ID 内置数据类型定义的(请参阅section 3.3.8 of the XML Schema Part 2: Datatypes)。
<xs:element name="foo">
<xs:complexType>
...
<xs:attribute name="bar" type="xs:ID"/>
...
</xs:complexType>
</xs:element>
虽然 DTD 不支持 XML Schema 中的丰富数据类型,但它确实支持有限的一组属性类型(在section 3.3.1 of XML 1.0 中定义)。这里讨论的属性是用ID 的属性类型定义的。
<!ATTLIST foo bar ID #IMPLIED>
使用上述 XML Schema 或 DTD,以下元素将由 ID 值“xyz”标识。
<foo bar="xyz"/>
如果不知道 XML Schema 或 DTD,就无法分辨什么是 ID,什么不是:
- 名称为“id”的属性不一定有ID的属性类型;和
- 名称不是“id”的属性可能具有 ID 的属性类型!
为了改善这种情况,随后发明了xml:id(参见xml:id W3C Recommendation)。这是一个始终具有相同前缀和名称的属性,旨在被视为 ID 为 attribute type 的属性。但是,它是否会取决于正在使用的解析器是否知道xml:id。由于许多解析器最初是在定义 xml:id 之前编写的,因此可能不受支持。
Java 中的 ID
在 Java 中,getElementById() 通过查找 type ID 的属性而不是 name 为“id”的属性来查找元素。
在上面的例子中,getElementById("xyz") 将返回 foo 元素,即使它上面的属性名称不是“id”(假设 DOM 知道 bar 具有 属性类型 的 ID)。
那么 DOM 是如何知道一个属性有什么属性类型的呢?有三种方式:
- 向解析器提供 XML Schema (example)
- 向解析器提供 DTD
- 向 DOM 明确指出它被视为 ID 的属性类型。
第三个选项是使用org.w3c.dom.Element class 上的setIdAttribute() 或setIdAttributeNS() 或setIdAttributeNode() 方法完成的。
Document doc;
Element fooElem;
doc = ...; // load XML document instance
fooElem = ...; // locate the element node "foo" in doc
fooElem.setIdAttribute("bar", true); // without this, 'found' would be null
Element found = doc.getElementById("xyz");
必须对每个具有这些类型属性之一的元素节点执行此操作。没有简单的内置方法可以使所有出现的具有给定名称(例如“id”)的属性都具有 属性类型 ID。
这第三种方法仅在调用getElementById() 的代码与创建DOM 的代码分开的情况下有用。如果是相同的代码,它已经找到了设置ID属性的元素,所以不太可能需要调用getElementById()。
另外,请注意,这些方法不在原始 DOM 规范中。 getElementById 是在 DOM level 2 中引入的。
XPath 中的 ID
原始问题中的 XPath 给出了结果,因为它只匹配属性 name。
要匹配属性类型 ID 值,需要使用 XPath id 函数(它是 Node Set Functions from XPath 1.0 之一):
id("xyz")
如果已使用,XPath 将给出与 getElementById() 相同的结果(即未找到匹配项)。
XML 中的 ID(续)
应突出显示 ID 的两个重要特征。
首先,属性类型ID的所有属性的值必须对整个XML文档是唯一的。在以下示例中,如果 personId 和 companyId 的 attribute type 为 ID,则添加另一个 ID 为 id24601 的 companyId 的公司将是错误的,因为它将与现有的 ID 值。即使属性名称不同,重要的是 属性类型。
<test1>
<person personId="id24600">...</person>
<person personId="id24601">...</person>
<company companyId="id12345">...</company>
<company companyId="id12346">...</company>
</test1>
其次,属性是在元素上定义的,而不是整个 XML 文档。因此,不同元素上具有相同属性名称的属性可能具有不同的 属性类型 属性。在以下示例 XML 文档中,如果只有 alpha/@bar 具有 ID 的 属性类型(并且没有其他属性),getElementById("xyz") 将返回一个元素,但 getElementById("abc") 不会(因为 @ 987654359@ 不是属性类型 ID)。此外,属性gamma/@bar 与alpha/@bar 具有相同的值也不是错误,因为它不是属性类型 em> 身份证。
<test2>
<alpha bar="xyz"/>
<beta bar="abc"/>
<gamma bar="xyz"/>
</test2>