Prophet
Prophet

Reputation: 33353

Updating XML file with TransformerFactory adds empty lines between nodes

I have the following method to update node values in XML file

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

Functionally it works.
The problem is that after each node update this code adds an empty lines between every file content lines (nodes).
Currently I use the code above to update the secret node value, but I don't think it matters what value do I update.
So from this

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<general>
    <environment>staging</environment>
    <tenantNameDev>automationdev</tenantNameDev>
    <tenantName>automation5</tenantName>
    <tenantNameProd>automation3</tenantNameProd>
    <userName>[email protected]</userName>
    <userNameDev>[email protected]</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>[email protected] </email>
        <alternativeWorkspaceId>81e15977-070a-4e68-8808-e2e6bb134f25</alternativeWorkspaceId>
        <alternativeEnvClientId>PQSWUCNXVRL1LALUJBRJ</alternativeEnvClientId>
        <alternativeSecret>VYpdpQ81n6p7i5C8FL2ni1RVOrHlD34ESxI1FW8U</alternativeSecret>
        <serverDeployDelay>3500</serverDeployDelay>
    </api>
</general>

After 4 calling the method above I receive this:

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




    <environment>staging</environment>




    <tenantNameDev>automationdev</tenantNameDev>




    <tenantName>automation5</tenantName>




    <tenantNameProd>automation3</tenantNameProd>




    <userName>[email protected]</userName>




    <userNameDev>[email protected]</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>[email protected] </email>




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



        <alternativeEnvClientId>PQSWUCNXVRL1LALUJBRJ</alternativeEnvClientId>




        <alternativeSecret>VYpdpQ81n6p7i5C8FL2ni1RVOrHlD34ESxI1FW8U</alternativeSecret>




        <serverDeployDelay>3500</serverDeployDelay>




    </api>




</general>

How can I prevent that?

Upvotes: 0

Views: 1203

Answers (2)

Yitzhak Khabinsky
Yitzhak Khabinsky

Reputation: 22157

Here is a conceptual example for XSLT.

The XSLT itself is somewhat generic. It should work for any XSLT without namespaces.

We are passing two parameters to XSLT, i.e. XML element name and its new value:

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

Input XML

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

Output 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>

Java

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>

Upvotes: 1

Michael Kay
Michael Kay

Reputation: 163262

You haven't shown your source XML or your stylesheet - options like xsl:strip-space and xsl:output indent="yes" make a big difference.

My guess would be that you are copying all of the whitespace text nodes from the source document, and only some of the element nodes.

Upvotes: 1

Related Questions