9

我正在尝试读取文件以生成 DOM 文档,但该文件有空格和换行符,我试图忽略它们,但我不能:

DocumentBuilderFactory docfactory=DocumentBuilderFactory.newInstance();
docfactory.setIgnoringElementContentWhitespace(true);

我在 Javadoc 中看到 setIgnoringElementContentWhitespace 方法仅在启用验证标志时运行,但我没有文档的 DTD 或 XML Schema。

我能做些什么?

更新

我不喜欢引入 mySelf < !ELEMENT... 声明的想法,我已经尝试了 Tomalak 指出的论坛中提出的解决方案,但它不起作用,我在 linux 环境中使用了 java 1.6。我想如果没有更多的提议,我会做一些方法来忽略空白文本节点

4

5 回答 5

11

'IgnoringElementContentWhitespace' 并不是要删除所有纯空白文本节点,仅删除其父级在模式中被描述为具有 ELEMENT 内容的空白节点——也就是说,它们只包含其他元素而不包含文本。

如果您没有使用模式(DTD 或 XSD),则元素内容默认为 MIXED,因此此参数将永远不会有任何效果。(除非解析器提供了一个非标准的 DOM 扩展来将所有未知元素视为包含 ELEMENT 内容,据我所知,可用于 Java 的那些没有。)

您可以在进入解析器的过程中破解文档以包含架构信息,例如通过将内部子集添加到包含 < !ELEMENT ... > 声明的 < !DOCTYPE ... [...] > 声明,然后使用 IgnoringElementContentWhitespace 参数。

或者,可能更简单,您可以在后期处理中或在它们使用 LSParserFilter 进入时去除空白节点。

于 2008-10-23T12:21:04.830 回答
6

这是一个(真的)迟到的答案,但这是我解决它的方法。我编写了自己的NodeList类实现。它只是忽略空的文本节点。代码如下:

private static class NdLst implements NodeList, Iterable<Node> {

    private List<Node> nodes;

    public NdLst(NodeList list) {
        nodes = new ArrayList<Node>();
        for (int i = 0; i < list.getLength(); i++) {
            if (!isWhitespaceNode(list.item(i))) {
                nodes.add(list.item(i));
            }
        }
    }

    @Override
    public Node item(int index) {
        return nodes.get(index);
    }

    @Override
    public int getLength() {
        return nodes.size();
    }

    private static boolean isWhitespaceNode(Node n) {
        if (n.getNodeType() == Node.TEXT_NODE) {
            String val = n.getNodeValue();
            return val.trim().length() == 0;
        } else {
            return false;
        }
    }

    @Override
    public Iterator<Node> iterator() {
        return nodes.iterator();
    }
}

然后,您将所有 s 包装NodeList在此类中,它将有效地忽略所有空白节点。(我将其定义为具有 0 长度修剪文本的文本节点。)

它还具有能够在 for-each 循环中使用的额外好处。

于 2011-05-01T22:29:12.147 回答
2

我通过这样做使它起作用

DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        dbFactory.setIgnoringElementContentWhitespace(true);
        dbFactory.setSchema(schema);
        dbFactory.setNamespaceAware(true);
NodeList nodeList = element.getElementsByTagNameNS("*", "associate");
于 2013-10-26T03:58:36.297 回答
1

我最终遵循了@bobince 使用 LSParserFilter 的想法。是的,该界面记录在https://docs.oracle.com/javase/7/docs/api/org/w3c/dom/ls/LSParserFilter.html但很难找到好的示例/解释材料。经过大量搜索后,我在http://www.informit.com/articles/article.aspx?p=31297&seqNum=29(Nicholas Chase,2003 年 3 月 14 日)找到了 DOM Level 3 Load and Save XML Reference Guide。这对我帮助很大。这是我的代码的一部分,它与 org.custommonkey.xmlunit 进行 XML 差异。(这是我自己写的一个工具,用来帮助我完成有偿工作,所以我留下了很多东西,比如更好的异常处理,以备不时之需。)

我特别喜欢使用 LSParserFilter,因为出于我的目的,我可能会在将来添加一个选项来忽略 id 属性,这应该是这个框架的一个简单增强。

// A small portion of my main class.
// Other imports may be necessary...
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.w3c.dom.ls.DOMImplementationLS;
import org.w3c.dom.ls.LSParser;
import org.w3c.dom.ls.LSParserFilter;

Document controlDoc = null;
Document testDoc = null;
try {
    System.setProperty(DOMImplementationRegistry.PROPERTY, "org.apache.xerces.dom.DOMImplementationSourceImpl");
    DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
    DOMImplementationLS impl = (DOMImplementationLS) registry.getDOMImplementation("LS");
    LSParser builder = impl.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, null);
    LSParserFilter filter = new InputFilter();
    builder.setFilter(filter);
    controlDoc = builder.parseURI(files[0].getPath());
    testDoc = builder.parseURI(files[1].getPath());
} catch (Exception exc) {
    System.out.println(exc.getMessage());
}

//--------------------------------------

import org.w3c.dom.ls.LSParserFilter;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.traversal.NodeFilter;

public class InputFilter implements LSParserFilter {

    public short acceptNode(Node node) {
        if (Utils.isNewline(node)) {
            return NodeFilter.FILTER_REJECT;
        }
        return NodeFilter.FILTER_ACCEPT;
    }

    public int getWhatToShow() {
        return NodeFilter.SHOW_ALL;
    }

    public short startElement(Element elem) {
        return LSParserFilter.FILTER_ACCEPT;
    }

}

//-------------------------------------
// From my Utils.java:

    public static boolean isNewline(Node node) {
        return (node.getNodeType() == Node.TEXT_NODE) && node.getTextContent().equals("\n");
    }
于 2018-07-07T02:34:58.703 回答
-2

试试这个:

private static Document prepareXML(String param) throws ParserConfigurationException, SAXException, IOException {

        param = param.replaceAll(">\\s+<", "><").trim();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setIgnoringElementContentWhitespace(true);
        DocumentBuilder builder = factory.newDocumentBuilder();
        InputSource in = new InputSource(new StringReader(param));
        return builder.parse(in);

    }
于 2018-02-16T22:44:17.640 回答