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

cig3rfwq  于 2022-12-25  发布在  Java
关注(0)|答案(5)|浏览(199)

我认为org.w3c.dom.NodeList接口缺少一个stream()函数来利用Java 8的流API的好处。考虑到引入默认方法来确保向后兼容性,我不明白为什么这个接口没有stream()函数。
所以我的问题是:

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

先谢了!
编辑:我目前正在使用这个工具 Package 器:

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();
}
kb5ga3dv

kb5ga3dv1#

DOM是一个奇怪的野兽,API是由W3C以一种独立于语言的方式定义的,然后Map到各种不同的编程语言,所以Java不能向核心DOM接口添加任何Java特有的东西,这些东西最初不属于DOM规范的一部分。
因此,虽然您不能将NodeList * 用作 * 流,但您可以轻松地从 * NodeList * 创建流,例如:

Stream<Node> nodeStream = IntStream.range(0, nodeList.getLength())
                                   .mapToObj(nodeList::item);

然而,有一个很大的警告-DOM NodeListlive 的,并且反映了自列表创建以来对原始DOM树的更改。如果您在DOM树中添加或删除元素,它们可能会神奇地从现有NodeList中出现或消失,如果这种情况发生在迭代中间,这可能会导致奇怪的效果。如果您想要一个“dead”节点列表,您需要将其复制到数组或列表中。就像你现在做的一样。

mmvthczy

mmvthczy2#

考虑到默认方法的引入以确保向后兼容性,我不明白为什么这个接口没有stream()函数。
该接口是在Java 8出现之前定义的,由于Stream在Java 8之前不存在,因此NodeList * 不能 * 支持它。
如何结合流API使用NodeList?
你不能。至少,不能直接说。
如果不鼓励这样做,原因是什么?
它不是“不鼓励”,而是不支持。
主要原因是历史,见上文。
负责为Java指定org.w3c.dom API的人(即W3联盟)可能会推出一个对Java 8更友好的API新版本。然而,这将引入一系列新的兼容性问题。新版本的API将与当前版本不兼容,也不兼容Java 8之前的JVM。
然而,这比仅仅让W3联盟更新API要复杂得多。
DOM API是在CORBA IDL中定义的,而JavaAPI是通过将CORBAJavaMap应用到IDL来“生成”的。此Map由OMG指定...而不是W3联盟。因此,创建org.w3c.domAPI的“Java8流友好”版本需要让OMG更新CORBAJavaMap,使其支持Stream(至少从CORBA兼容性的Angular 来看,这是有问题的)或者中断API和CORBA之间的连接。
不幸的是,了解OMG世界在更新IDL到JavaMap方面发生了什么(如果有的话)是很困难的......除非您为OMG成员组织工作,等等。

6tqwzwtp

6tqwzwtp3#

下面是一个使用流来查找特定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;
}
ngynwnxp

ngynwnxp4#

java8流迭代
像这样使用:

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

对于java9 iterate,iterate有一个增强版本,而以前的版本也可用:

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

两个版本的iterate在Java14中仍然相同

xlpyo6sf

xlpyo6sf5#

如果您只想将子节点转换为节点元素流,则可使用以下方法:

private Stream<Element> nodeLisToStreamElements(NodeList nodeList) {
    return IntStream.range(0, nodeList.getLength())
        .mapToObj(nodeList::item)
        .filter(node -> node instanceof Element)
        .map(node -> (Element) node);
}

相关问题