【问题标题】:Trouble parsing an XML file with a compiled XPATH expression?使用已编译的 XPATH 表达式解析 XML 文件时遇到问题?
【发布时间】:2012-06-02 10:30:49
【问题描述】:

我正在处理a tutorial 并遇到了一个我预计会解决的问题。我希望有人可以帮助我处理这段代码。我过不了这个。如果我使用 XPATH 表达式“//*/text()”,我在下面共享的这段代码将匹配,但是当我得到比这更具体并使用“//tag0”时它无法匹配:G/text()" 。知道我做错了什么吗?我只是想从下面提供的 XML 中获取 2 个“tag0:G”值:

import java.io.IOException;
import java.io.StringReader;    
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;    
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;    
public class Test1 {        
  public static void main(String[] args) {
    System.out.println("Test start...");
    String myXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
    "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\">" +
    "<soapenv:Body>" +
    "<tag0:getA xmlns:tag0=\"http://me.ws.ix\">" +
    "<tag0:B>" +
    "<tag0:CC>" +
    "<tag0:CC>" +
    "<tag0:D>false</tag0:D>" +
    "<tag0:E>false</tag0:E>" +
    "<tag0:F xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>" +
    "<tag0:G>10001</tag0:G>" +
    "<tag0:H>7744000002</tag0:H>" +
    "</tag0:CC>" +
    "<tag0:CC>" +
    "<tag0:D>false</tag0:D>" +
    "<tag0:E>false</tag0:E>" +
    "<tag0:F xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"/>" +
    "<tag0:G>20002</tag0:G>" +
    "<tag0:H>1111122222</tag0:H>" +
    "</tag0:CC>" +
    "</tag0:CC>" +
    "<tag0:I>2012-05-27 23:38:48</tag0:I>" +
    "</tag0:B>" +
    "</tag0:getA>" +
    "</soapenv:Body>" +
    "</soapenv:Envelope>";

    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(true);
    Document doc = null;
    NodeList nodes = null;
    try {           
      doc = factory.newDocumentBuilder().parse( new InputSource( new StringReader( myXML) ) );
      XPathExpression expr = XPathFactory.newInstance().newXPath()
        .compile("//tag0:G/text()"); // this fails, I don't know why
      nodes = (NodeList)expr.evaluate(doc, XPathConstants.NODESET);
    } catch (SAXException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    } catch (ParserConfigurationException e) {
      e.printStackTrace();
    } catch (XPathExpressionException e) {
      e.printStackTrace();
    }
    System.out.println("Nodes length: " + nodes.getLength() );
    for (int i = 0; i < nodes.getLength(); i++) { 
      String val = nodes.item(i).getNodeValue(); 
      System.out.println( "Val: " + val ); 
    }
    System.out.println("Test end...");
  }    
}

【问题讨论】:

  • 提供的信息不足,无法回答。失败了怎么办? “更具体”,例如什么?
  • 我提供了一个完全工作的代码 sn-p 来演示这个问题。这怎么不够?
  • 如果您运行代码,您会注意到没有堆栈跟踪。这个问题不是关于错误,而是关于 xpath 与我期望它匹配的内容不匹配。
  • @djangofan 期望人们运行你的代码是非常乐观的。您应该提供足够的细节,以便有足够经验的读者能够看到问题。
  • 如果某件事失败了,你应该说它是如何失败的。当我们诊断问题时,我们首先查看的是错误消息(或者如果它是不正确的结果,我们会查看不正确的结果。)否决。

标签: java xml xpath xml-parsing


【解决方案1】:

在开始编译 XPath 表达式之前,您应该在您的 XPath 实例上注册一个 NamespaceContext。你可以使用XPath#setNamespaceContext(NamespaceContex nsContext)

请阅读 xml.apache.org 上的 using NamespaceContext chapter

这个想法是,当您的文档使用名称空间信息进行解析时,XPath 执行器需要知道如何将您使用的前缀与您运行它的文档中的名称空间 URI 相匹配。前缀本身什么也没说,您可以使用任意前缀,只要它映射到相同的 URI。

附言Namespaces in XML 上还有更多矿石。

【讨论】:

  • 好的,我明白你的意思了。我仍然在学习。谢谢。为什么通配符表达式会起作用?这让我失望了。
  • 这是不同的。通过让你的 DOM 工厂命名空间知道你确保你的解析将保留命名空间信息。您现在还需要告诉您的 XPath 您的前缀是什么意思。请按照我提供的链接进行操作,它应该开始变得更有意义。如果您仍有疑问,请告诉我
  • @djangofan,我们每天都在学习。通配符有效,因为 XPath 中的 * 匹配任何元素。它并不关心元素的实际命名空间,因为它与 * 表达式的任何其他命名空间一样好。
  • 事实证明这很容易,而且现在很有意义。很高兴终于可以理解 XML 命名空间(至少我认为我理解)。
【解决方案2】:

当然,你也可以作弊——如果每次出现的“G”(或你之后的任何元素)都来自同一个命名空间——你可以简单地做

//*[local-name()='G'] 

但是,虽然这有效,但这只是在规避问题。你还不如硬着头皮跨过命名空间……

【讨论】:

    猜你喜欢
    • 2023-03-26
    • 1970-01-01
    • 2012-02-06
    • 1970-01-01
    • 2013-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多