如何在读取文件时忽略空格以生成XML DOM

时间:2008-10-23 10:55:26

标签: java xml whitespace

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

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

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

我该怎么办?

更新

我不喜欢介绍mySelf< !ELEMENT ...声明,我试过了 在Tomalak指出的forum中提出的解决方案,但它不起作用,我在linux环境中使用了java 1.6。我想如果不再提议,我会用一些方法来忽略空白文本节点

5 个答案:

答案 0 :(得分:10)

'IgnoringElementContentWhitespace'不是要删除所有纯空白文本节点,只有空格在模式中描述为具有ELEMENT内容的空格节点 - 也就是说,它们只包含其他元素和从不发短信。

如果您没有使用架构(DTD或XSD),则元素内容默认为MIXED,因此此参数将永远不会产生任何影响。 (除非解析器提供非标准的DOM扩展来将所有未知元素视为包含ELEMENT内容,据我所知,Java可用的内容不是。)

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

或者,可能更容易,您可以在后期处理中或在使用LSParserFilter进入时删除空白节点。

答案 1 :(得分:5)

这是一个(真的)迟到的答案,但这是我如何解决它。我编写了自己的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();
    }
}

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

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

答案 2 :(得分:2)

我这样做是有效的

DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        dbFactory.setIgnoringElementContentWhitespace(true);
        dbFactory.setSchema(schema);
        dbFactory.setNamespaceAware(true);
NodeList nodeList = element.getElementsByTagNameNS("*", "associate");

答案 3 :(得分: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上的《 DOM Level 3加载和保存XML参考指南》(Nicholas Chase,2003年3月14日)。那对我有很大帮助。这是我的代码的一部分,它与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");
    }

答案 4 :(得分:0)

试试这个:

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);

    }