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

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

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

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

我能做什么?

更新

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

‘IgnoringElementContentWhitespace’不是要删除所有纯空白文本节点,只是删除其父项在模式中描述为具有ELEMENT内容的空白节点 – 也就是说,它们只包含其他元素而从不包含文本。

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

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

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

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

 private static class NdLst implements NodeList, Iterable { private List nodes; public NdLst(NodeList list) { nodes = new ArrayList(); 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 iterator() { return nodes.iterator(); } } 

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

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

我这样做是有效的

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

尝试这个:

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

我最终关注@ 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差异。 (这是一个用我自己的时间编写的工具来帮助我完成付费工作,所以我留下了很多东西,比如更好的exception处理,因为事情很慢。)

我特别喜欢使用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"); }