Node.getTextContent()有没有一种方法可以获取当前节点的文本内容,而不是后代节点的文本?

16

Node.getTextContent() 返回当前节点及其后代节点的文本内容。

是否有一种方法可以获取当前节点的文本内容,而不是后代节点的文本内容。

示例

<paragraph>
    <link>XML</link>
    is a 
    <strong>browser based XML editor</strong>
    editor allows users to edit XML data in an intuitive word processor.
</paragraph>

期望的输出结果

paragraph = is a editor allows users to edit XML data in an intuitive word processor.
link = XML
strong = browser based XML editor

我尝试了以下代码

String str =            "<paragraph>"+
                            "<link>XML</link>"+
                            " is a "+ 
                            "<strong>browser based XML editor</strong>"+
                            "editor allows users to edit XML data in an intuitive word processor."+
                        "</paragraph>";

        org.w3c.dom.Document domDoc = null;
        DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder;

        try {
            docBuilder = docFactory.newDocumentBuilder();
            ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());
            domDoc = docBuilder.parse(bis);         
        } catch (ParserConfigurationException e1) {         
            e1.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }       

        DocumentTraversal traversal = (DocumentTraversal) domDoc;
        NodeIterator iterator = traversal.createNodeIterator(
                domDoc.getDocumentElement(), NodeFilter.SHOW_ELEMENT, null, true);

        for (Node n = iterator.nextNode(); n != null; n = iterator.nextNode()) {           
            String tagname = ((Element) n).getTagName();
            System.out.println(tagname + "=" + ((Element)n).getTextContent());
        }

但它给出的输出看起来像这样

paragraph=XML is a browser based XML editoreditor allows users to edit XML data in an intuitive word processor.
link=XML
strong=browser based XML editor

请注意段落元素包含了链接加粗标签的文本,而我不想要它们。有什么建议吗?

4个回答

15
你想要的是过滤节点<paragraph>的子节点,只保留节点类型为Node.TEXT_NODE的节点。
这是一个可以返回所需内容的方法示例。
public static String getFirstLevelTextContent(Node node) {
    NodeList list = node.getChildNodes();
    StringBuilder textContent = new StringBuilder();
    for (int i = 0; i < list.getLength(); ++i) {
        Node child = list.item(i);
        if (child.getNodeType() == Node.TEXT_NODE)
            textContent.append(child.getTextContent());
    }
    return textContent.toString();
}

在您的示例中,它的意思是:

String str = "<paragraph>" + //
        "<link>XML</link>" + //
        " is a " + //
        "<strong>browser based XML editor</strong>" + //
        "editor allows users to edit XML data in an intuitive word processor." + //
        "</paragraph>";
Document domDoc = null;
try {
    DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
    ByteArrayInputStream bis = new ByteArrayInputStream(str.getBytes());
    domDoc = docBuilder.parse(bis);
} catch (Exception e) {
    e.printStackTrace();
}
DocumentTraversal traversal = (DocumentTraversal) domDoc;
NodeIterator iterator = traversal.createNodeIterator(domDoc.getDocumentElement(), NodeFilter.SHOW_ELEMENT, null, true);
for (Node n = iterator.nextNode(); n != null; n = iterator.nextNode()) {
    String tagname = ((Element) n).getTagName();
    System.out.println(tagname + "=" + getFirstLevelTextContent(n));
}

输出:

paragraph= is a editor allows users to edit XML data in an intuitive word processor.
link=XML
strong=browser based XML editor

该函数遍历一个节点的所有子元素,只保留文本内容 (排除注释、节点等),并累加它们各自的文本内容。

NodeElement中没有直接获取一级文本内容的方法。


3
如果你将最后一个for循环改为以下内容,它将按照你的期望行事。
for (Node n = iterator.nextNode(); n != null; n = iterator.nextNode()) {           
    String tagname = ((Element) n).getTagName();
    StringBuilder content = new StringBuilder();
    NodeList children = n.getChildNodes();
    for(int i=0; i<children.getLength(); i++) {
        Node child = children.item(i);
        if(child.getNodeName().equals("#text"))
            content.append(child.getTextContent());
    }
    System.out.println(tagname + "=" + content);
}

2
我使用Java 8流和辅助类来完成此操作:
import java.util.*;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class NodeLists
{
    /** converts a NodeList to java.util.List of Node */
    static List<Node> list(NodeList nodeList)
    {
        List<Node> list = new ArrayList<>();
        for(int i=0;i<nodeList.getLength();i++) {list.add(nodeList.item(i));}
        return list;
    }
}

然后

 NodeLists.list(node)
.stream()
.filter(node->node.getNodeType()==Node.TEXT_NODE)
 .map(Node::getTextContent)
 .reduce("",(s,t)->s+t);

使用您的代码“原样” - 获取编译器错误The method filter((<no type> node) -> {}) is undefined for the type List<Node> - JGlass
这是3年后,但我认为我只是在.filter(...之前忘记了.stream() - Konrad Höffner
你真厉害!解决了问题,谢谢。我在Java 8和流功能方面是新手。再次感谢您的帮助和快速响应 - 我希望您的答案能够帮助我,因为我遇到了与原始OP相同的问题!祝你晚上愉快,祝你博士学业顺利! - JGlass

1

隐式地,实际节点文本没有任何功能,但是通过一个简单的技巧,您可以实现它。如果节点getTextContent()包含“\ n”,则询问,如果是这种情况,则实际节点没有任何文本。

希望这有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接