如何在Java 8 Stream API中使用org.w3c.dom.NodeList?

时间:2014-04-29 09:08:16

标签: java dom

我认为接口org.w3c.dom.NodeList缺少stream()函数,以利用Java 8的Stream API的优势。考虑引入默认方法以确保向后兼容性,我无法理解为什么此接口没有stream()功能。

所以我的问题是:

  • 如何将NodeList与Stream API结合使用?
  • 如果不鼓励这样做,原因是什么?

提前致谢!

编辑:我目前正在使用此实用程序包装器:

private static Stream<Node> nodeStream(NodeList list) {
    List<Node> nodes = new ArrayList<>();

    for (int n = 0; n < list.getLength(); ++n) {
        nodes.add(list.item(n));
    }

    return nodes.stream();
}

4 个答案:

答案 0 :(得分:47)

DOM是一个奇怪的野兽,由W3C以与语言无关的方式定义API,然后映射到各种不同的编程语言,因此Java无法添加任何特定于Java的核心DOM接口。首先是DOM规范的一部分。

因此,虽然您无法将NodeList 用作流,但您可以使用例如<{1}}轻松地创建来自的流

NodeList

然而,有一个重要的警告 - DOM Stream<Node> nodeStream = IntStream.range(0, nodeList.getLength()) .mapToObj(nodeList::item); live ,并反映自创建列表以来对原始DOM树的更改。如果在DOM树中添加或删除元素,它们可能会从现有的NodeLists中神奇地出现或消失,如果在迭代中发生这种情况,这可能会导致奇怪的效果。如果你想要一个“死”节点列表,你需要将它复制到一个数组或列表中,就像你已经做的那样。

答案 1 :(得分:5)

  

考虑引入默认方法以确保向后兼容性,我无法理解为什么此接口没有stream()函数。

接口是在Java 8存在之前定义的。由于{8}之前不存在Stream,因此NodeList 无法支持它。

  

如何将NodeList与Stream API结合使用?

你做不到。至少,不是直接。

  

如果不鼓励这样做,原因是什么?

不是“气馁”。相反,它不受支持。

主要原因是历史。见上文。

负责指定Java org.w3c.dom API(即W3联盟)的人员可能会推出一个对Java 8更友好的新版API。但是,这将引入一堆新的兼容性问题。新版本的API不会与当前版本的二进制兼容,并且与Java 8之前的JVM不兼容。


然而,它比让W3联盟更新API更复杂。

DOM API在CORBA IDL中定义,并且通过将CORBA Java映射应用于IDL来“生成”Java API。此映射由OMG ...而不是W3 Consortium指定。因此,创建org.w3c.dom API的“Java 8 Stream友好”版本需要让OMG更新CORBA Java映射以Stream知道(从CORBA兼容性角度来看,这将是有问题的,在至少)或破坏Java API和CORBA之间的连接。

不幸的是,发现OMG世界中正在发生的关于刷新IDL到Java映射的内容(如果有的话)很难......除非您为OMG成员组织工作,等等。我没有。

答案 2 :(得分:1)

以下是使用stream查找特定NodeList元素的示例:

private String elementOfInterest;       // id of element
private String elementOfInterestValue;  // value of element

public boolean searchForElementOfInterest(Document doc)
{
        boolean bFound=false;
        NodeList nList = doc.getElementsByTagName("entity");

        // since NodeList does not have stream implemented, then use this hack
        Stream<Node> nodeStream = IntStream.range(0, nList.getLength()).mapToObj(nList::item);
        // search for element of interest in the NodeList
        if(nodeStream.parallel().filter(this::isElementOfInterest).collect(Collectors.toList()).size() > 0)
                bFound=true;

        return bFound;
}

private boolean isElementOfInterest(Node nNode)
{
        boolean bFound=false;
        assert(nNode != null);
        if (nNode.getNodeType() == Node.ELEMENT_NODE) {
                Element eElement = (Element) nNode;
                String id = eElement.getElementsByTagName("id").item(0).getTextContent();
                String data = eElement.getElementsByTagName("data").item(0).getTextContent();
                if (id.contentEquals(elementOfInterest) && data.contentEquals(elementOfInterestValue))
                        bFound = true;
        }
        return bFound;
}

答案 3 :(得分:0)

java8 Stream.iterate
像这样使用:

Stream.iterate(0, i -> i + 1)
      .limit (nodeList.getLength())
      .map (nodeList::item).forEach...