我目前手动生成NodeList
所有文档节点(按文档顺序)。得到这个的 XPath 表达式NodeList
是
//. | //@* | //namespace::*
我第一次尝试手动遍历 DOM 并收集节点(NodeSet
是委托给 a 的原始NodeList
实现List
):
private static void walkRecursive(Node cur, NodeSet nodes) {
nodes.add(cur);
if (cur.hasAttributes()) {
NamedNodeMap attrs = cur.getAttributes();
for (int i=0; i < attrs.getLength(); i++) {
Node child = attrs.item(i);
walkRecursive(child, nodes);
}
}
int type = cur.getNodeType();
if (type == Node.ELEMENT_NODE || type == Node.DOCUMENT_NODE) {
NodeList children = cur.getChildNodes();
if (children == null)
return;
for (int i=0; i < children.getLength(); i++) {
Node child = children.item(i);
walkRecursive(child, list);
}
}
}
我会通过调用walkRecursive(doc, nodes)
where doc
is theorg.w3c.Document
和nodes
a (yet empty)来开始递归NodeSet
。
我使用这个原始 XML 文档对此进行了测试:
<?xml version="1.0"?>
<myns:root xmlns:myns="http://www.my.ns/#">
<myns:element/>
</myns:root>
例如,如果我将手动创建NodeSet
的和NodeList
由最初提到的 XPath 表达式生成的规范化,并逐字节比较这两个字节,那么结果是相等的,并且似乎工作得很好。
但是,如果我遍历这两个NodeList
s 并打印调试信息(typeString
只需生成一个字符串表示)
for (int i=0; i < nodes.getLength(); i++) {
Node child = nodes.item(i);
System.out.println("Type: " + typeString(child.getNodeType()) +
" Name:" + child.getNodeName() +
" Local name: " + child.getLocalName() +
" NS: " + child.getNamespaceURI());
}
然后我收到 XPath 生成的输出NodeList
:
Type: DocumentNode Name:#document Local name: null NS: null
Type: Element Name:myns:root Local name: root NS: http://www.my.ns/#
Type: Attribute Name:xmlns:myns Local name: myns NS: http://www.w3.org/2000/xmlns/
Type: Attribute Name:xmlns:xml Local name: xml NS: http://www.w3.org/2000/xmlns/
Type: Text Name:#text Local name: null NS: null
Type: Element Name:myns:element Local name: element NS: http://www.my.ns/#
Type: Text Name:#text Local name: null NS: null
这对于手动生成的NodeList
:
Type: DocumentNode Name:#document Local name: null NS: null
Type: Element Name:myns:root Local name: root NS: http://www.my.ns/#
Type: Attribute Name:xmlns:myns Local name: myns NS: http://www.w3.org/2000/xmlns/
Type: Text Name:#text Local name: null NS: null
Type: Element Name:myns:element Local name: element NS: http://www.my.ns/#
Type: Text Name:#text Local name: null NS: null
因此,如您所见,在第一个示例中,NodeList 还包含Node
XML 命名空间:
Type: Attribute Name:xmlns:xml Local name: xml NS: http://www.w3.org/2000/xmlns/
现在我的问题:
a)如果我正确解释了xml-names11,那么我不需要 xmlns:xml 声明:
前缀 xml 根据定义绑定到命名空间名称http://www.w3.org/XML/1998/namespace。它可以,但不需要,被声明,并且不能被未声明或绑定到任何其他命名空间名称。其他前缀不得绑定到此名称空间名称,并且不得将其声明为默认名称空间。
我对么?(至少 c)暗示那个方向)
b) 但是,为什么 XPath 评估还是要添加它——它不应该只包括一开始就存在的东西,而不是自动添加东西吗?
c) 这可能会导致XML 规范化出现问题,尽管它不应该xml
-在规范化期间应该省略命名空间的声明。有谁知道出错的(Java)实现?
编辑:
这是我用来评估包含“xml”命名空间节点的 XPath 表达式的代码:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setValidating(false);
InputStream in = ...;
try {
Document doc = dbf.newDocumentBuilder().parse(in);
XPathFactory fac = XPathFactory.newInstance();
XPath xp = fac.newXPath();
XPathExpression exp = xp.compile("//. | //@* | //namespace::*");
NodeList nodes = (NodeList)exp.evaluate(doc, XPathConstants.NODESET);
} finally {
in.close();
}