2011-08-09 56 views
4

我当前手动生成所有文档节点的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)其中docorg.w3c.Documentnodes 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(); 
} 
+0

我没有得到这额外的属性(jdk1.6.0_18) –

+0

@Maurice:奇怪,即使使用JDK 5和7,我也会得到它。我将添加用于评估XPath表达式的代码。 – emboss

+0

我的错误,我误解了你的帖子 –

回答

1

既然你可以写

<myns:root xml:space="preserve" xmlns:myns="http://www.my.ns/#"> 
    <myns:element/> 
</myns:root> 

没有声明“xml”前缀,那么它必须隐含在那里。因此,正确的,包括在//namespace:*定位步骤

所以这个命名空间声明的命名空间节点,

一)你错了,你需要它(当然,这取决于你的代码的目的)

b)见上

c)否,但我看到其他的命名空间的角落情况下,事情失控了(如Problem with conversion of org.dom4j.Document to org.w3c.dom.Document and XML Signature