【问题标题】:Fetch XML-Nodes by Path按路径获取 XML 节点
【发布时间】:2014-02-21 11:03:58
【问题描述】:

我有以下(非常大 => 5GB)XML:

<Hotels>
  <Hotel>
    <Name>Hotel 1</Name>
    <City>City 1</City>
    <Phone>12345</Phone>
  </Hotel>
  <Hotel>
    <Name>Hotel 2</Name>
    <City>City 2</City>
    <Phone>67890</Phone>
  </Hotel>
  ...
</Hotels>

我有一个文件,它定义了我要提取哪些字段以及它们的路径:

$root = "/Hotels/Hotel";
$fields = array("HotelName"   => "/Name",
                "PhoneNumber" => "/Phone");

所以HotelName 的路径是:/Hotels/Hotel/Name。

现在我想获取每家酒店的信息。我无法为它们创建类(如here),因为脚本必须是动态的,并且将传递具有不同定义文件的不同 XML 文件。

如何通过使用路径、无类且内存使用率低(=> 大文件)来解决此问题?

//编辑:一切都实现了。我只需要一种方法来遍历 Hotel 并使用我拥有的路径获取它们的值。

【问题讨论】:

  • 对于“非常大”(有多大?)XML 文件,您可能需要考虑将其转储到关系数据库(看起来这个 XML 文件实际上代表一个表)或使用像 Basex 这样的原生 XML 数据库。
  • 这些文件有多大?
  • 文件可以是 5 GB 大。我将它们导出为 csv,因此我可以使用“LOAD DATA INFILE”将它们导入 MySQL。
  • 写一个 sax 解析器可能会更好

标签: java xml xpath


【解决方案1】:

尝试阅读本教程,其中有一些解释和示例。 http://viralpatel.net/blogs/java-xml-xpath-tutorial-parse-xml/

对于您的 porpuse,您应该使用来自 Stax 家族的东西,而不是 DOM。

试试这个

public class QueryXML {
  public void query() throws ParserConfigurationException, SAXException,
      IOException, XPathExpressionException {
    // standard for reading an XML file
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    factory.setNamespaceAware(true);
    DocumentBuilder builder;
    Document doc = null;
    XPathExpression expr = null;
    builder = factory.newDocumentBuilder();
    doc = builder.parse("person.xml");

    // create an XPathFactory
    XPathFactory xFactory = XPathFactory.newInstance();

    // create an XPath object
    XPath xpath = xFactory.newXPath();

    // compile the XPath expression
    expr = xpath.compile("//person[firstname='Lars']/lastname/text()");
    // run the query and get a nodeset
    Object result = expr.evaluate(doc, XPathConstants.NODESET);

    // cast the result to a DOM NodeList
    NodeList nodes = (NodeList) result;
    for (int i=0; i<nodes.getLength();i++){
      System.out.println(nodes.item(i).getNodeValue());
    }

    // new XPath expression to get the number of people with name Lars
    expr = xpath.compile("count(//person[firstname='Lars'])");
    // run the query and get the number of nodes
    Double number = (Double) expr.evaluate(doc, XPathConstants.NUMBER);
    System.out.println("Number of objects " +number);

    // do we have more than 2 people with name Lars?
    expr = xpath.compile("count(//person[firstname='Lars']) >2");
    // run the query and get the number of nodes
    Boolean check = (Boolean) expr.evaluate(doc, XPathConstants.BOOLEAN);
    System.out.println(check);
  }

您可以简单地调整该代码以满足您的需求。

【讨论】:

  • 你告诉我不要使用 DOM,然后你发布了一个带有 DOM 示例的链接和代码......!?
【解决方案2】:

如果您已经找到 &lt;Hotel/&gt; 节点并将其作为 DOM 引用,只需访问其子节点(将酒店作为上下文)。要么使用

  • XPath:./Name或更短的Name(只是不要以/开头,它指的是根),但请确保使用酒店节点作为查询上下文;或
  • DOM:hotel.getChildNodes(),然后遍历结果集,比较元素名称以找到相应的子节点。

【讨论】:

  • 谢谢,但我不能先建立整个文件的文档。它太大了,无法加载到内存中。
  • 如果您正在处理大型 XML 文档,请考虑使用专门为此而编写的 XML 数据库。 BaseX 和 eXist DB 是一些开源示例,也可以从 Java 接口。学习曲线有些陡峭(如果您已经了解 XPath,它会有所帮助),但值得付出努力。否则,您将无法使用类似 SAX 的方法扫描文档。
猜你喜欢
  • 2020-12-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-27
  • 1970-01-01
  • 2017-07-04
  • 2018-11-21
相关资源
最近更新 更多