Reputation: 133
i have a xml like this
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Empleado>
<ConsultorTecnico>
<Nombre>Pablo</Nombre>
<Legajo antiguedad="4 meses">7778</Legajo>
</ConsultorTecnico>
<CNC>
<Nombre>Brian</Nombre>
<Legajo antiguedad="1 año, 7 meses">2134</Legajo>
<Sueldo>4268.0</Sueldo>
</CNC>
</Empleado>
What i want is to read a XML and append "Sueldo" at the same level than "Nombre" and "Legajo" in the element "CNC". "Sueldo" must be "Legajo" x 2
The code I have appends "Sueldo" as you can see in the XML above but it does not indent it as it should, Im using the propierties to indent (This XML is created the same way, using DOM)
public class Main
{
public static void main(String[] args)
{
try
{
File xml = new File("C:\\Empleado.xml");
if (xml.exists() == true)
{
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(xml);
String legajo = doc.getElementsByTagName("Legajo").item(1).getFirstChild().getNodeValue();
Element sueldo = doc.createElement("Sueldo");
Node valorSueldo = doc.createTextNode(String.valueOf(Float.valueOf(legajo)*2));
sueldo.appendChild(valorSueldo);
Node cnc = doc.getElementsByTagName("CNC").item(0);
cnc.appendChild(sueldo);
DOMSource source = new DOMSource(doc);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount","2");
FileOutputStream fos = new FileOutputStream("C:\\Empleado.xml");
StreamResult sr = new StreamResult(fos);
t.transform(source,sr);
}
else
throw new Exception("No hay archivo XML con ese nombre en el directorio");
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
}
Thank you in advance guys, I'll appreciate the help here!
Upvotes: 4
Views: 3158
Reputation: 122364
Assuming your input file is the same as the output you've shown but without the Sueldo
element, then the initial CNC
element has five child nodes as far as the DOM is concerned
<CNC>
and <Nombre>
Nombre
element node</Nombre>
and <Legajo
Legajo
element node</Legajo>
and </CNC>
You are inserting the Sueldo
element after this final text node, which produces
<CNC>
<Nombre>Brian</Nombre>
<Legajo antiguedad="1 año, 7 meses">2134</Legajo>
<Sueldo>4268.0</Sueldo></CNC>
and the INDENT
output property simply moves the closing </CNC>
tag to the next line, aligned with the opening one. To get the auto indentation to do the right thing you would need to remove all the whitespace-only text nodes from the initial tree.
Alternatively, forget the auto-indentation and do it yourself - instead of adding Sueldo
as the last child of CNC
(after that final text node), instead add a newline-and-four-spaces text node immediately after the Legajo
(i.e. before the last text node) and then add the Sueldo
element after that.
As an alternative approach entirely, I would consider doing the transformation in XSLT rather than using the DOM APIs
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<!-- ignore whitespace-only text nodes in the input -->
<xsl:strip-space elements="*"/>
<!-- and re-indent the output -->
<xsl:output method="xml" indent="yes" />
<!-- Copy everything verbatim except where otherwise specified -->
<xsl:template match="@*|node()">
<xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy>
</xsl:template>
<!-- For CNC elements, add a Sueldo as the last child -->
<xsl:template match="CNC">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
<Sueldo><xsl:value-of select="Legajo * 2" /></Sueldo>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
which you could either run using the TransformerFactory
API from Java code or using a standalone command-line XSLT processor.
Upvotes: 1
Reputation: 7799
XML does not intrinsically define any indentation or pretty-form. If you want it to be "indented", you need to insert content with newlines and spaces. In this case, you need content immediately after element Legajo
and before element Sueldo
.
To my taste, the best strategy is to ignore all formatting from XML files and use generalized prettyfiers immediately before human consumption. Or, better, give them good XML editors. If you have every program that manipulates XML files concerned about this detail, most of the benefits of XML are gone (and a lot of effort misused).
UPDATE: Just noticed that you are using element CNC
to "position" the insert, not Legajo
. The space-and-newlines content needs to go immediately before element CNC
(and after element Sueldo
).
Upvotes: 0