20

简而言之; 我在 XML 文件中生成了许多空行,我正在寻找一种将它们删除的方法,以作为倾斜文件的一种方式。我怎样才能做到这一点 ?

详细解释;我目前有这个 XML 文件:

<recent>
  <paths>
    <path>path1</path>
    <path>path2</path>
    <path>path3</path>
    <path>path4</path>
  </paths>
</recent>

我使用此 Java 代码删除所有标签,并添加新标签:

public void savePaths( String recentFilePath ) {
    ArrayList<String> newPaths = getNewRecentPaths();
    Document recentDomObject = getXMLFile( recentFilePath );  // Get the <recent> element.
    NodeList pathNodes = recentDomObject.getElementsByTagName( "path" );   // Get all <path> nodes.

    //1. Remove all old path nodes :
        for ( int i = pathNodes.getLength() - 1; i >= 0; i-- ) { 
            Element pathNode = (Element)pathNodes.item( i );
            pathNode.getParentNode().removeChild( pathNode );
        }

    //2. Save all new paths :
        Element pathsElement = (Element)recentDomObject.getElementsByTagName( "paths" ).item( 0 );   // Get the first <paths> node.

        for( String newPath: newPaths ) {
            Element newPathElement = recentDomObject.createElement( "path" );
            newPathElement.setTextContent( newPath );
            pathsElement.appendChild( newPathElement );
        }

    //3. Save the XML changes :
        saveXMLFile( recentFilePath, recentDomObject ); 
}

多次执行此方法后,我得到了一个具有正确结果的 XML 文件,但在“路径”标记之后和第一个“路径”标记之前有许多空行,如下所示:

<recent>
  <paths>





    <path>path5</path>
    <path>path6</path>
    <path>path7</path>
  </paths>
</recent>

任何人都知道如何解决这个问题?

------------------------------------------------------- 编辑:添加 getXMLFile(. ..)、saveXMLFile(...) 代码。

public Document getXMLFile( String filePath ) { 
    File xmlFile = new File( filePath );

    try {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document domObject = db.parse( xmlFile );
        domObject.getDocumentElement().normalize();

        return domObject;
    } catch (Exception e) {
        e.printStackTrace();
    }

    return null;
}

public void saveXMLFile( String filePath, Document domObject ) {
    File xmlOutputFile = null;
    FileOutputStream fos = null;

    try {
        xmlOutputFile = new File( filePath );
        fos = new FileOutputStream( xmlOutputFile );
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
        transformer.setOutputProperty( "{http://xml.apache.org/xslt}indent-amount", "2" );
        DOMSource xmlSource = new DOMSource( domObject );
        StreamResult xmlResult = new StreamResult( fos );
        transformer.transform( xmlSource, xmlResult );  // Save the XML file.
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (TransformerConfigurationException e) {
        e.printStackTrace();
    } catch (TransformerException e) {
        e.printStackTrace();
    } finally {
        if (fos != null)
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
}
4

11 回答 11

27

首先,解释为什么会发生这种情况——这可能有点离题,因为您没有包含用于将 XML 文件加载到 DOM 对象中的代码。

根据 DOM 规范,当您从文件中读取 XML 文档时,标签之间的空格实际上构成了有效的 DOM 节点。因此,XML 解析器将每个这样的空格序列视为一个 DOM 节点(类型为TEXT);

为了摆脱它,我可以想到三种方法:

  • 将 XML 与架构相关联,然后setValidating(true)在.setIgnoringElementContentWhitespace(true)DocumentBuilderFactory

    (注意:setIgnoringElementContentWhitespace仅当解析器处于验证模式时才有效,这就是您必须使用的原因setValidating(true)

  • 编写一个 XSL 来处理所有节点,过滤掉只有空白的TEXT节点。
  • 使用 Java 代码执行此操作:使用 XPath 查找所有仅空白TEXT节点,遍历它们并从其父节点中删除每个节点(使用getParentNode().removeChild())。这样的事情会做(doc将是你的 DOM 文档对象):

    XPath xp = XPathFactory.newInstance().newXPath();
    NodeList nl = (NodeList) xp.evaluate("//text()[normalize-space(.)='']", doc, XPathConstants.NODESET);
    
    for (int i=0; i < nl.getLength(); ++i) {
        Node node = nl.item(i);
        node.getParentNode().removeChild(node);
    }
    
于 2012-10-01T08:57:24.480 回答
4

在删除所有旧的“路径”节点后,我能够通过使用此代码来解决此问题:

while( pathsElement.hasChildNodes() )
    pathsElement.removeChild( pathsElement.getFirstChild() );

这将删除 XML 文件中所有生成的空格。

特别感谢MadProgrammer对上述有用链接的评论。

于 2012-10-01T13:12:48.940 回答
2

如果您只需要快速“清理”您的 xml,您可以查看类似的内容。然后你可以有一个方法,如:

public static String cleanUp(String xml) {
    final StringReader reader = new StringReader(xml.trim());
    final StringWriter writer = new StringWriter();
    try {
        XmlUtil.prettyFormat(reader, writer);
        return writer.toString();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return xml.trim();
}

此外,如果需要,比较 anche 检查差异:XMLUnit

于 2012-10-01T08:45:50.637 回答
2

我遇到了同样的问题,很长一段时间我都不知道,但现在,在布拉德的这个问题和他自己对他自己问题的回答之后,我发现了问题所在。

我必须添加我自己的答案,因为布拉德的答案并不完美,艾萨克是如何说的:

我不会盲目地删除子节点而不知道它们是什么

因此,更好的“解决方案”(引用是因为它更有可能是解决方法)是:

pathsElement.setTextContent("");

这完全删除了无用的空行。这绝对比删除所有子节点要好。布拉德,这也应该对你有用。

但是,这是一个结果,而不是原因,我们知道如何消除这个结果,而不是原因。

原因是:当我们调用时removeChild(),它删除了这个孩子,但它留下了被删除的孩子的缩进,并且也有换行符。而这个 indent_and_like_break 被视为文本内容。

因此,要消除原因,我们应该弄清楚如何消除 child 及其 indent。欢迎来到我关于这个的问题。

于 2013-01-10T09:57:14.373 回答
1

如果使用 DOM 处理 API(例如 DOM4J),有一种非常简单的方法可以去除空行:

  • 将要保留的文本放在变量中(即text
  • 使用将节点文本设置为“”node.setText("")
  • 将节点文本设置为text使用node.setText(text)

瞧!没有更多的空行。其他答案很好地描述了 xml 输出中的额外空行实际上是文本类型的额外节点。

这种技术可以与任何 DOM 解析系统一起使用,只要将文本设置函数的名称更改为适合您 API 中的名称,因此表示它的方式稍微抽象一点。

希望这可以帮助:)

于 2014-05-09T10:00:23.257 回答
1

就我而言,我将其转换为字符串,然后只是做了一个正则表达式:

        //save as String
        StringWriter writer = new StringWriter();
        StreamResult result = new StreamResult(writer);
        tr.transform(new DOMSource(document), result);
        strResult = writer.toString();

        //remove empty lines 
        strResult = strResult.replaceAll("\\n\\s*\\n", "\n");
于 2021-05-06T14:08:43.647 回答
0

几点注意事项:1)当您操作 XML(删除元素/添加新元素)时,我强烈建议您使用 XSLT(而不是 DOM)2)当您通过 XSLT 转换 XML 文档时(就像您在保存方法中所做的那样) ,将 OutputKeys.INDENT 设置为“no” 3) 对于 xml 的简单后处理(删除空格、注释等),您可以使用简单的 SAX2 过滤器

于 2012-10-01T08:41:05.377 回答
0
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setIgnoringElementContentWhitespace(true);
于 2013-11-05T18:15:20.253 回答
0

我正在使用以下代码:

System.out.println("Start remove textnode");
        i=0;
        while (parentNode.getChildNodes().item(i)!=null) {
            System.out.println(parentNode.getChildNodes().item(i).getNodeName());
            if (parentNode.getChildNodes().item(i).getNodeName().equalsIgnoreCase("#text")) {
                parentNode.removeChild(parentNode.getChildNodes().item(i));
                System.out.println("text node removed");
            }
            i=i+1;

        }
于 2014-07-11T06:48:41.923 回答
0

当我使用 dom4j 删除一些元素并且遇到同样的问题时,上面的解决方案在不添加其他一些必需的 jar 的情况下没有用。最后,我找到了一个简单的解决方案,只需要使用 JDK io pakage:

  1. 使用 BufferedReader 读取 xml 文件并过滤空行。
StringBuilder stringBuilder = new StringBuilder();
FileInputStream fis = new FileInputStream(outFile);
InputStreamReader isr = new InputStreamReader(fis);
BufferedReader br = new BufferedReader(isr);
String s;
while ((s = br.readLine()) != null) {
  if (s.trim().length() > 0) {
    stringBuilder.append(s).append("\n");
  }
}
  1. 将字符串写入xml文件
OutputStreamWriter osw = new OutputStreamWriter(fou);
BufferedWriter bw = new BufferedWriter(osw);
String str = stringBuilder.toString();
bw.write(str);
bw.flush();
  1. 记得关闭所有流
于 2020-06-04T01:31:17.143 回答
0

很晚的答案,但也许它仍然对某人有帮助。

我在课堂上有这段代码,文档是在转换后构建的(就像你一样):

TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");

将最后一行更改为

transformer.setOutputProperty(OutputKeys.INDENT, "no");
于 2022-01-03T16:19:38.930 回答