【问题标题】:How to remove extra empty lines from XML file?如何从 XML 文件中删除多余的空行?
【发布时间】:2012-09-22 02:10:06
【问题描述】:

简而言之;我在 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();
            }
    }
}

【问题讨论】:

标签: java xml carriage-return code-cleanup


【解决方案1】:

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

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

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

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

    (注意: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);
    }
    

【讨论】:

  • 我不知道该怎么做 :),但我已将 getXMLFile(...) 代码添加到问题中。
  • 另一种可能性是定义一个 XML 模式来验证文档,然后结合使用 DocumentBuilderFactory 的“setIgnoringElementContentWhitespace”和“setValidating”。给这只猫剥皮的方法很多。
  • 我怎样才能删除

    标签中的新行,例如:

    细胞色素 P450 还原酶(NADPH-细胞色素 P450 氧化还原酶;EC 1.6.2.4;缩写为 POR或 CPR) 是外源代谢酶细胞色素 P450 (P450) 超家族的关键电子供体。它还在内源性代谢中发挥许多重要作用,将电子传递给一系列受体,包括细胞色素 b5(支持脂肪酸去饱和酶和延长酶活性)、角鲨烯单加氧酶(甾醇生物合成酶

【解决方案2】:

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

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

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

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

【讨论】:

  • 我不会喜欢盲目地删除子节点而不知道它们是什么。至少,我会在这里包含一个测试,看看我真的 am 删除了一个空文本节点(使用 'getNodeType' 和 'getNodeValue')。
  • @Isaac .. 我同意你的观点,但就我而言,我确信它们都是空的,因为我自己已经删除了它们。相反,如果有东西丢失并且没有被删除,那么我想删除它:)
  • @Brad,请检查我的答案:goo.gl/06Qd9,我解释了如何在不盲目删除所有子节点的情况下删除这些空行,并写了一些关于这种行为的原因。
【解决方案3】:

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

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

【讨论】:

    【解决方案4】:

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

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

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

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

    pathsElement.setTextContent("");
    

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

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

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

    所以,要消除原因,我们应该弄清楚如何消除孩子及其缩进。欢迎来到我的question about this

    【讨论】:

    • 是的,简单得多...假设您确实想在不知道它们是什么的情况下盲目地删除所有子节点。 :-)
    【解决方案5】:

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

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

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

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

    希望这会有所帮助:)

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        【解决方案7】:
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setIgnoringElementContentWhitespace(true);
        

        【讨论】:

        • 这不会忽略新生成的 XML 中的空白。测试了这个。
        【解决方案8】:

        我正在使用以下代码:

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

        【讨论】:

          【解决方案9】:

          当我使用 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. 记得关闭所有流

          【讨论】:

            【解决方案10】:

            在我的例子中,我将它转换为一个字符串,然后只是做了一个正则表达式:

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

            【讨论】:

            • 是的,当您需要字符串时非常理想。
            【解决方案11】:

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

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

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

            将最后一行改为

            transformer.setOutputProperty(OutputKeys.INDENT, "no");
            

            【讨论】:

            • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-08-07
            • 1970-01-01
            • 1970-01-01
            • 2022-01-19
            • 2017-01-15
            • 1970-01-01
            • 2015-10-01
            相关资源
            最近更新 更多