javaxmldom:id属性有什么特殊性?

javaxmldom:id属性有什么特殊性?,java,dom,Java,Dom,Document类的javadoc在getElementById下有以下注释 注意:名为“ID”或“ID”的属性不属于ID类型,除非这样定义 因此,我将一个XHTML文档读入DOM(使用Xerces 2.9.1) 文档中有一个普通的旧 我调用getElementById(“fribble”),它返回null 我使用XPath获取“/*[id='fribble']”,一切正常 因此,问题是,是什么导致DocumentBuilder实际将ID属性标记为“如此定义?”对于getElementById(

Document
类的javadoc在
getElementById
下有以下注释

注意:名为“ID”或“ID”的属性不属于ID类型,除非这样定义

因此,我将一个XHTML文档读入DOM(使用Xerces 2.9.1)

文档中有一个普通的旧

我调用
getElementById(“fribble”)
,它返回null

我使用XPath获取“/*[id='fribble']”,一切正常


因此,问题是,是什么导致
DocumentBuilder
实际将ID属性标记为“如此定义?”

对于
getElementById()
调用,
文档必须知道其节点的类型,并且目标节点必须是XML ID类型,方法才能找到它。它通过关联的模式知道其元素的类型。如果未设置架构,或者未将
id
属性声明为XML id类型,
getElementById()
将永远找不到它

我猜您的文档不知道
p
元素的
id
属性是XML id类型(是吗?)。您可以使用
getChildNodes()
和其他DOM遍历函数导航到DOM中的节点,并尝试在id属性上调用
Attr.isId()
,以确定是否正确

从javadoc:

DOM实现预计将 使用属性Attr.isId可以 确定属性是否为类型 身份证

注意:名称为“ID”或 “id”不是id类型,除非如此 已定义。


如果使用
DocumentBuilder
将XML解析为DOM,请确保在调用newDocumentBuilder()之前调用DocumentBuilderFactory,以确保从工厂获得的生成器知道元素类型。

ID属性不是名为“ID”的属性,它是由DTD或模式声明为ID属性的属性。例如,html 4 DTD对其进行了描述:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

对应的xpath表达式实际上是
id('fribble')
,它应该返回与
getElementById
相同的结果。为此,与文档关联的dtd或模式必须将属性声明为ID类型


如果您控制查询的xml,您还可以尝试根据将属性重命名为
xml:id

这些属性之所以特殊,是因为它们的类型,而不是因为它们的名称

XML格式的ID

虽然很容易将属性视为
name=“value”
,因为值是一个简单的字符串,但这并不是全部内容——还有一个属性类型与属性关联

当涉及XML模式时,这很容易理解,因为XML模式支持XML元素和XML属性的数据类型。XML属性被定义为简单类型(例如xs:string、xs:integer、xs:dateTime、xs:anyURI)。这里讨论的属性是用
xs:ID
内置数据类型定义的(请参阅)

使用上述XML模式或DTD,以下元素将由ID值“xyz”标识

必须对每个元素节点执行此操作,这些节点上有一个此类属性。没有简单的内置方法可以使具有给定名称(例如“id”)的属性的所有引用都是属性类型id

第三种方法仅在调用
getElementById()
的代码与创建DOM的代码分离的情况下有用。如果是相同的代码,它已经找到了设置ID属性的元素,因此不太可能需要调用
getElementById()

另外,请注意,这些方法不在原始DOM规范中。中引入了
getElementById

XPath中的ID

原始问题中的XPath给出了一个结果,因为它只匹配属性名

要匹配属性类型ID值,需要使用XPath
ID
函数(它是以下函数之一):

如果使用了它,XPath将给出与
getElementById()
相同的结果(即未找到匹配项)

XML中的ID续

应该突出显示ID的两个重要特性

首先,属性类型ID的所有属性的值必须是整个XML文档唯一的。在下面的示例中,如果
personId
companyId
都具有ID属性类型,则添加另一个ID为
companyId
的公司将是错误的,因为它将是现有ID值的副本。尽管属性名称不同,但重要的是属性类型

<test1>
 <person personId="id24600">...</person>
 <person personId="id24601">...</person>
 <company companyId="id12345">...</company>
 <company companyId="id12346">...</company>
</test1>

以下内容将允许您按id获取元素:

public static Element getElementById(Element rootElement, String id)
{
    try 
    {
        String path = String.format("//*[@id = '%1$s' or @Id = '%1$s' or @ID = '%1$s' or @iD = '%1$s' ]", id);
        XPath xPath = XPathFactory.newInstance().newXPath();
        NodeList nodes = (NodeList)xPath.evaluate(path, rootElement, XPathConstants.NODESET);

        return (Element) nodes.item(0);
    } 
    catch (Exception e) 
    {
        return null;
    }
}

不幸的是,到目前为止,指向模式示例的链接已经失效。
<foo bar="xyz"/>
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("xyz")
<test1>
 <person personId="id24600">...</person>
 <person personId="id24601">...</person>
 <company companyId="id12345">...</company>
 <company companyId="id12346">...</company>
</test1>
<test2>
  <alpha bar="xyz"/>
  <beta bar="abc"/>
  <gamma bar="xyz"/>
</test2>
public static Element getElementById(Element rootElement, String id)
{
    try 
    {
        String path = String.format("//*[@id = '%1$s' or @Id = '%1$s' or @ID = '%1$s' or @iD = '%1$s' ]", id);
        XPath xPath = XPathFactory.newInstance().newXPath();
        NodeList nodes = (NodeList)xPath.evaluate(path, rootElement, XPathConstants.NODESET);

        return (Element) nodes.item(0);
    } 
    catch (Exception e) 
    {
        return null;
    }
}