首页 > 解决方案 > 使用 TransformerFactory 更新 XML 文件会在节点之间添加空行

问题描述

我有以下方法来更新 XML 文件中的节点值

static public void updateRepositoryValue(String fileName, String xpath, String value){
    try {
        String rootPath = Paths.get(".").toAbsolutePath().normalize().toString();
        String path = rootPath + "/src/main/resources/repository/" + fileName + ".xml";
        DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
        DocumentBuilder b = f.newDocumentBuilder();
        Document doc = b.parse(new File(path));

        XPath xPath = XPathFactory.newInstance().newXPath();
        Node updatedNode = (Node) xPath.compile(xpath).evaluate(doc, XPathConstants.NODE);
        updatedNode.setTextContent(value);

        Transformer tf = TransformerFactory.newInstance().newTransformer();
        tf.setOutputProperty(OutputKeys.INDENT, "yes");
        tf.setOutputProperty(OutputKeys.METHOD, "xml");
        tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

        DOMSource domSource = new DOMSource(doc);
        StreamResult sr = new StreamResult(new File(path));
        tf.transform(domSource, sr);
    }catch (Exception e){
        e.printStackTrace();
    }
}

从功能上讲,它有效。
问题是在每个节点更新后,此代码在每个文件内容行(节点)之间添加一个空行。
目前我使用上面的代码来更新secret节点值,但我认为更新什么值并不重要。
所以从这

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<general>
    <environment>staging</environment>
    <tenantNameDev>automationdev</tenantNameDev>
    <tenantName>automation5</tenantName>
    <tenantNameProd>automation3</tenantNameProd>
    <userName>automation5@yahoo.com</userName>
    <userNameDev>automationdev@yahoo.com</userNameDev>
    <incompleteDetailsNotification>Some of the details are incomplete or invalid</incompleteDetailsNotification>
    <ui>
        <multiValueAtt>Gender</multiValueAtt>
        <incompleteDetailsNotification>Some of the details are incomplete or invalid</incompleteDetailsNotification>
    </ui>
    <api>
        <ownerIdAnn>3052cb88-a5a6-40db-af95-e1225ecf45fe</ownerIdAnn>
        <schemaIdAnn>f60566b1-be2b-40b1-9663-a7bb52ba2d3f</schemaIdAnn>
        <ownerId>e3bd1480-09b5-4268-9126-6962238e9a1e</ownerId>
        <schemaId>fd2941ad-276e-42b7-88fb-5054e8acdc8c</schemaId>
        <ownerIdProd>5218f707-96de-4d4c-92c6-ebedd9ccbdbf</ownerIdProd>
        <schemaIdProd>f50f2ac3-8e38-4733-adac-4817e3c58643</schemaIdProd>
        <envClientId>PYJYF7XU017OGFH5RJ8Q</envClientId>
        <secret>6MmE3bELLzO29r1ToG7LoVspWqanNJNGZCP0tG0N</secret>
        <workspaceId>e3bd1480-09b5-4268-9126-6962238e9a1e</workspaceId>
        <partnerId>b0f95322-a898-4af1-8fc1-9a8951d0c13a</partnerId>
        <email>kukussfds@mailinator.com </email>
        <alternativeWorkspaceId>81e15977-070a-4e68-8808-e2e6bb134f25</alternativeWorkspaceId>
        <alternativeEnvClientId>PQSWUCNXVRL1LALUJBRJ</alternativeEnvClientId>
        <alternativeSecret>VYpdpQ81n6p7i5C8FL2ni1RVOrHlD34ESxI1FW8U</alternativeSecret>
        <serverDeployDelay>3500</serverDeployDelay>
    </api>
</general>

4调用上面的方法后,我收到:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<general>




    <environment>staging</environment>




    <tenantNameDev>automationdev</tenantNameDev>




    <tenantName>automation5</tenantName>




    <tenantNameProd>automation3</tenantNameProd>




    <userName>automation5@yahoo.com</userName>




    <userNameDev>automationdev@yahoo.com</userNameDev>




    <incompleteDetailsNotification>Some of the details are incomplete or 
invalid</incompleteDetailsNotification>




    <ui>




        <multiValueAtt>Gender</multiValueAtt>




        <incompleteDetailsNotification>Some of the details are incomplete or invalid</incompleteDetailsNotification>




    </ui>




    <api>




        <ownerIdAnn>3052cb88-a5a6-40db-af95-e1225ecf45fe</ownerIdAnn>




        <schemaIdAnn>f60566b1-be2b-40b1-9663-a7bb52ba2d3f</schemaIdAnn>




        <ownerId>e3bd1480-09b5-4268-9126-6962238e9a1e</ownerId>




        <schemaId>fd2941ad-276e-42b7-88fb-5054e8acdc8c</schemaId>




        <ownerIdProd>5218f707-96de-4d4c-92c6-ebedd9ccbdbf</ownerIdProd>




        <schemaIdProd>f50f2ac3-8e38-4733-adac-4817e3c58643</schemaIdProd>




        <envClientId>PYJYF7XU017OGFH5RJ8Q</envClientId>




        <secret>6MmE3bELLzO29r1ToG7LoVspWqanNJNGZCP0tG0N</secret>




        <workspaceId>e3bd1480-09b5-4268-9126-6962238e9a1e</workspaceId>




        <partnerId>b0f95322-a898-4af1-8fc1-9a8951d0c13a</partnerId>




        <email>kukussfds@mailinator.com </email>




        <alternativeWorkspaceId>81e15977-070a-4e68-8808-e2e6bb134f25</alternativeWorkspaceId>



        <alternativeEnvClientId>PQSWUCNXVRL1LALUJBRJ</alternativeEnvClientId>




        <alternativeSecret>VYpdpQ81n6p7i5C8FL2ni1RVOrHlD34ESxI1FW8U</alternativeSecret>




        <serverDeployDelay>3500</serverDeployDelay>




    </api>




</general>

我怎样才能防止这种情况?

标签: javaxml

解决方案


这是 XSLT 的概念示例。

XSLT 本身有些通用。它应该适用于任何没有名称空间的 XSLT。

我们将两个参数传递给 XSLT,即 XML 元素名称及其新值:

transformer.setParameter("elementToFind", "test2");
transformer.setParameter("elementValue", "Prophet");

输入 XML

<?xml version="1.0"?>
<test>
   <abc value="10">data1</abc>
   <bbc value="200">data2</bbc>
   <abc value="20">
      <test2>subdata1</test2>
   </abc>
</test>

输出 XML

<?xml version='1.0' encoding='utf-8' ?>
<test>
  <abc value="10">data1</abc>
  <bbc value="200">data2</bbc>
  <abc value="20">
    <test2>Prophet</test2>
  </abc>
</test>

爪哇

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;

public class Process3 {
    public static void main(String[] args) {
        String XSLTFILE = "e:\\Temp\\Process.xslt";
        String INFILE = "e:/Temp/Input.xml";
        String OUTFILE = "e:/Temp/Output.xml";

        try {
            // I/O
            StreamSource input = new StreamSource(new File(INFILE));
            StreamSource xslt = new StreamSource(new File(XSLTFILE));
            StreamResult output = new StreamResult(new File(OUTFILE));

            // Transformation
            TransformerFactory factory = TransformerFactory.newInstance();
            Transformer transformer = factory.newTransformer(xslt);

            // XSLT parameters
            transformer.setParameter("elementToFind", "test2");
            transformer.setParameter("elementValue", "Prophet");
            transformer.transform(input, output);
        } catch (TransformerConfigurationException tce) {
            tce.printStackTrace();
        } catch (TransformerException te) {
            te.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

XSLT

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="no"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="elementToFind" select="'test2'"/>
    <xsl:param name="elementValue" select="'Prophet'"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[local-name()=$elementToFind]">
        <xsl:copy>
            <xsl:value-of select="$elementValue"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

推荐阅读