我当前手动生成所有文档节点的NodeList
(按文档顺序)。 XPath表达式得到这个NodeList
是手动创建所有文档节点的节点列表
//. | //@* | //namespace::*
我手动遍历DOM和收集节点第一次尝试(NodeSet
是一种原始的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)
其中doc
是org.w3c.Document
和nodes
a(尚空)NodeSet
。
我测试此使用这个原语的XML文档:
<?xml version="1.0"?>
<myns:root xmlns:myns="http://www.my.ns/#">
<myns:element/>
</myns:root>
如果我例如规范化我的手动创建NodeSet
和由最初提到的XPath表达式生成的NodeList
以及用于字节比较两个字节,那么结果是平等的,似乎工作得很好。
但是,如果我遍历两个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
所以,你可以看到,在第一个例子中的节点列表还包含了XML命名空间Node
:
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 canonicalization出现问题,虽然它的shouldn't - 在规范化过程中应该省略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();
}
我没有得到这额外的属性(jdk1.6.0_18) –
@Maurice:奇怪,即使使用JDK 5和7,我也会得到它。我将添加用于评估XPath表达式的代码。 – emboss
我的错误,我误解了你的帖子 –