I have the following code to convert text file to xml.:-
**
public static void main (String args[]) {
new ToXML().doit();
}
public void doit () {
try{
in = new BufferedReader(new FileReader("D:/sample.txt"));
out = new StreamResult("D:/data.xml");
initXML();
String str;
while ((str = in.readLine()) != null)
{
process(str);
}
in.close();
writeXML();
}
catch (Exception e) { e.printStackTrace(); }
}
public void initXML() throws ParserConfigurationException{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
DOMImplementation impl = builder.getDOMImplementation();
xmldoc = impl.createDocument(null, "AIRLINE_INFO", null);
root = xmldoc.getDocumentElement();
}
public void process(String s) {
String elements = s;
Element e1 = xmldoc.createElement("Supplier_Name");
Node n1 = xmldoc.createTextNode(elements);
e1.appendChild(n1);
Element e2 = xmldoc.createElement("E-Mail_Address");
Node n2 = xmldoc.createTextNode(elements);
e2.appendChild(n2);
e0.appendChild(e1);
e0.appendChild(e2);
root.appendChild(e0);
}
public void writeXML() throws TransformerConfigurationException,
TransformerException {
DOMSource domSource = new DOMSource(xmldoc);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING,"ISO-8859-1");
transformer.setOutputProperty
("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(domSource, out);
}
}
**
The output which is Expected is:
**
<AIRLINE_INFO>
<AIRTICKET>
<Supplier_Name>SpiceJet Ltd, 319, Udyog Vihar, Phase IV, Gurgaon - 122016 Haryana, India</Supplier_Name>
<E-Mail_Address>E-Mail: custrelations#spicejet.com</E-Mail_Address>
</AIRTICKET>
</AIRLINE_INFO>
**
But Currently While Excuting the code i am getting the following output
**
<AIRLINE_INFO>
<AIRTICKET>
<Supplier_Name>SpiceJet Ltd, 319, Udyog Vihar, Phase IV, Gurgaon - 122016 Haryana, India</Supplier_Name>
<E-Mail_Address>SpiceJet Ltd, 319, Udyog Vihar, Phase IV, Gurgaon - 122016 Haryana, India</E-Mail_Address>
</AIRTICKET>
<AIRTICKET>
<Supplier_Name>E-Mail: custrelations#spicejet.com</Supplier_Name>
<E-Mail_Address>E-Mail: custrelations#spicejet.com</E-Mail_Address>
</AIRTICKET>
</AIRLINE_INFO>
**
Please help how can i break the object in order to achieve the Expected output.
You use two times the same string for the text nodes here:
String elements = s;
Element e1 = xmldoc.createElement("Supplier_Name");
Node n1 = xmldoc.createTextNode(elements);
e1.appendChild(n1);
Element e2 = xmldoc.createElement("E-Mail_Address");
Node n2 = xmldoc.createTextNode(elements);
e2.appendChild(n2);
To fix that, you need to read two lines, and then create one air ticket node with that information.
Related
I have a problem where I sign xml document and validate signature after that and the validation passes, but when I serialize document to byte array and then deserialize it back to document, signature validation fails.
Here are methods used for validation and serialization/deserialization:
public class DocumentSigner {
#Override
public byte[] transformToByteArray(Document doc) throws Exception {
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
ByteArrayOutputStream os = new ByteArrayOutputStream();
transformer.transform(new DOMSource(doc), new StreamResult(os));
return os.toByteArray();
}
private Document byteArrayToXmlDoc(byte[] documentoXml) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new ByteArrayInputStream(documentoXml), "UTF-8");
}
#Override
public Boolean validate(byte[] byteArrayDoc, Integer certificatePropertiesId) throws Exception {
Document doc = byteArrayToXmlDoc(byteArrayDoc);
return validate(doc, certificatePropertiesId);
}
public Boolean validate(Document doc, Integer certificatePropertiesId) throws Exception {
NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS,
"Signature");
if (nl.getLength() == 0) {
throw new Exception("No signature element.");
}
KeyStore ks = KeyStore.getInstance("JKS");
CertificatePropertiesDTO certProp = databaseLogic.getCertificateProperties(certificatePropertiesId);
if (certProp == null || certProp.getCertificatePassword().isEmpty() || certProp.getCertificate() == null){
throw new RuntimeException("No certificate.");
}
ks.load(new ByteArrayInputStream(certProp.getCertificate()), certProp.getCertificatePassword().toCharArray());
KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(ks.aliases().nextElement(), new KeyStore.PasswordProtection(certProp.getCertificatePassword().toCharArray()));
X509Certificate[] certs = (X509Certificate[]) keyEntry.getCertificateChain();
if (certs == null || certs.length == 0) {
throw new RuntimeException("No certificate found.");
}
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
DOMValidateContext valContext = new DOMValidateContext(keyEntry.getCertificate().getPublicKey(), nl.item(0));
NodeList els = doc.getElementsByTagNameNS("*", "SignatureProperties");
Element el = (Element) els.item(0);
valContext.setIdAttributeNS(el, null, "Id");
valContext.setDefaultNamespacePrefix("dsig");
valContext.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE);
try {
XMLSignature signature2 = fac
.unmarshalXMLSignature(new DOMStructure(nl.item(0)));
boolean coreValidity = signature2.validate(valContext);
// Check core validation status.
if (coreValidity == false) {
log.info("Signature failed core validation");
boolean sv = signature2.getSignatureValue()
.validate(valContext);
log.info("signature validation status: " + sv);
Iterator<?> i = signature2.getSignedInfo().getReferences()
.iterator();
for (int j = 0; i.hasNext(); j++) {
Reference ref = (Reference) i.next();
boolean refValid = ref.validate(valContext);
log.info("ref[" + j + "] validity status: " + refValid);
}
return false;
} else {
log.info("Signature passed core validation");
return true;
}
} catch (Exception ex) {
log.info("EXCEPTION during validation: " + ex.getMessage());
return false;
}
}
public void signDocument(Document doc)
{
....
}
public void writeToDisk(String path, String rac)
{
BufferedWriter writer = null;
try
{
writer = new BufferedWriter(new FileWriter(path));
writer.write(rac);
}
catch ( IOException e)
{
}
finally
{
try
{
if ( writer != null)
writer.close( );
}
catch ( IOException e)
{
try {
throw e;
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
#Override
public String transformToString(Document doc,
Boolean omitXmlDeclaration) throws Exception {
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
//transformerFactory.setAttribute("indent-number", 4);
Transformer transformer = transformerFactory.newTransformer();
if (omitXmlDeclaration)
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,
"yes");
// transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
//
StringWriter sw = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(sw));
//String output = sw.getBuffer().toString().replaceAll("\n|\r", "");
return sw.toString();
}
}
Here is where it passes/fails:
public void SignAndValidate()
{
...
Document doc = createDocument();
documentSigner.signDocument(doc);
validate(doc, 1);
// OUTPUT:
// Signature passed core validation
byte[] docArr = documentSigner.transformToByteArray(doc);
validate(docArr, 1);
// OUTPUT:
// Signature failed core validation
// signature validation status: false
// ref[0] validity status: false
// ref[1] validity status: true
}
If necessary I will post methods for creating/signing document but it's big.
Here is the signing method:
private void signDocument(Document document) throws Exception {
//Remove ApacheXMLDSig because after every SOAP message signing it's set as default provdier, but doesn't know about here() function from XPATH2
Security.removeProvider("ApacheXMLDSig");
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM", "XMLDSig");
String id = String.format("id%s", UUID.randomUUID().toString());
KeyStore ks = KeyStore.getInstance("JKS");
CertificatePropertiesDTO certProp = databaseLogic.getCertificateProperties(1);
if (certProp == null || certProp.getCertificatePassword().isEmpty() || certProp.getCertificate() == null){
throw new RuntimeException("No certificate.");
}
ks.load(new ByteArrayInputStream(certProp.getCertificate()), certProp.getCertificatePassword().toCharArray());
KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(ks.aliases().nextElement(), new KeyStore.PasswordProtection(certProp.getCertificatePassword().toCharArray()));
X509Certificate[] certs = (X509Certificate[]) keyEntry.getCertificateChain();
if (certs == null || certs.length == 0) {
throw new RuntimeException("No certificate found.");
}
Element propSig = XMLElement(document, "PROP_Sig", "");
Attr propNS = XMLAtribut(document, "xmlns", "http://ns.adobe.com/pdf/2006");
propSig.setAttributeNodeNS(propNS);
propSig.setAttribute("type", "cabinet");
DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssZZ");
Element m = XMLElement(document, "M", String.format("D:%s", df.format(new Date())));
m.setAttribute("type", "text");
Element name = XMLElement(document, "Name", cert.getSubjectX500Principal().getName());
name.setAttribute("type", "text");
propSig.appendChild(m);
propSig.appendChild(name);
SignatureProperty sp = sigFactory.newSignatureProperty(Collections.singletonList(new DOMStructure(propSig)), "data_signature", null);
SignatureProperties sps = sigFactory.newSignatureProperties(Collections.singletonList(sp), id);
CanonicalizationMethod cm = sigFactory.newCanonicalizationMethod(CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS, (XMLStructure) null);
SignatureMethod sm = sigFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, null);
DigestMethod dm1 = sigFactory.newDigestMethod(DigestMethod.SHA1, null);
Transform tf1 = sigFactory.newTransform(CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS, (TransformParameterSpec) null);
Reference ref1 = sigFactory.newReference("#" + id, dm1, Collections.singletonList(tf1), "http://www.w3.org/2000/09/xmldsig#SignatureProperties", null);
DigestMethod dm2 = sigFactory.newDigestMethod(DigestMethod.SHA1, null);
String here = "here()/ancestor::dsig:Signature[1]/../../../../../..//. | "
+ "here()/ancestor::dsig:Signature[1]/../../../../../..//#* | "
+ "here()/ancestor::dsig:Signature[1]/../../../../../..//namespace::*";
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("dsig", "http://www.w3.org/2000/09/xmldsig#");
XPathType xp = new XPathType(here, XPathType.Filter.INTERSECT, hm);
TransformParameterSpec paramsXPath2= new XPathFilter2ParameterSpec(Collections.singletonList(xp));
Transform tf2 = sigFactory.newTransform(Transform.XPATH2, paramsXPath2);
Transform tf3 = sigFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null);
Transform tf4 = sigFactory.newTransform(CanonicalizationMethod.EXCLUSIVE_WITH_COMMENTS, (TransformParameterSpec) null); //"http://www.w3.org/2001/10/xml-exc-c14n#WithComments"
List<Transform> lt2 = new ArrayList<Transform>();
lt2.add(tf2);
lt2.add(tf3);
lt2.add(tf4);
Reference ref2 = sigFactory.newReference("", dm2, lt2, null, null);
List<Reference> lr = new ArrayList<Reference>();
lr.add(ref1);
lr.add(ref2);
SignedInfo si = sigFactory.newSignedInfo(cm, sm, lr);
KeyInfoFactory kif = KeyInfoFactory.getInstance("DOM", "XMLDSig");
ArrayList<Object> x509Content = new ArrayList<>();
for (int i = 0; i < certs.length; i++) {
x509Content.add(certs[i]);
}
X509Data xd = kif.newX509Data(x509Content);
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd));
DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), document.getElementsByTagName("sac:SignatureInformation").item(0));
XMLSignature signature =
sigFactory.newXMLSignature(si, ki, Collections.singletonList( sigFactory.newXMLObject(Collections.singletonList(sps), null, null, null)), "data_signature", null);
dsc.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE);
dsc.setDefaultNamespacePrefix("dsig");
try {
signature.sign(dsc);
}
catch (Exception ex) {
log.warn(ex.getMessage());
throw new RuntimeException("Signing failed");
}
}
Here is part of sample XML document which is signed:
<ext:UBLExtension>
<ext:ExtensionContent>
<sig:UBLDocumentSignatures>
<sac:SignatureInformation>
<dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Id="data_signature">
<dsig:SignedInfo>
<dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
<dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<dsig:Reference Type="http://www.w3.org/2000/09/xmldsig#SignatureProperties" URI="#idfe5688f4-583f-4a98-b26c-9d651b2f8918">
<dsig:Transforms>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<dsig:DigestValue>iq802IBHl5kVdIMWA5Wlb5hYEoY=</dsig:DigestValue>
</dsig:Reference>
<dsig:Reference URI="">
<dsig:Transforms>
<dsig:Transform Algorithm="http://www.w3.org/2002/06/xmldsig-filter2">
<dsig:XPath Filter="intersect" xmlns:dsig="http://www.w3.org/2002/06/xmldsig-filter2">here()/ancestor::dsig:Signature[1]/../../../../../..//. | here()/ancestor::dsig:Signature[1]/../../../../../..//#* | here()/ancestor::dsig:Signature[1]/../../../../../..//namespace::*</dsig:XPath>
</dsig:Transform>
<dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<dsig:DigestValue>2jmj7l5rSw0yVb/vlWAYkK/YBwk=</dsig:DigestValue>
</dsig:Reference>
</dsig:SignedInfo>
<dsig:SignatureValue>d+DRc25SXnhxwXJs10A9Hnf1g0gG2bZqqnpTbZvrzp8X3EvtOVr3dBP6Ldc1RMTJYSF+guanlWKn
liaKlu7VbdB+SiQRuAMAZt+9Cnbn0CMlIzt22nRJNzjbeLBpCm7K63jCHGOXsWCW43DI/DYeZwq+
Q2j7WESgOtWLqUO0Jn8=</dsig:SignatureValue>
<dsig:KeyInfo>
<dsig:X509Data>
<dsig:X509Certificate>...</dsig:X509Certificate>
<dsig:X509Certificate>...</dsig:X509Certificate>
</dsig:X509Data>
</dsig:KeyInfo>
<dsig:Object>
<dsig:SignatureProperties Id="idfe5688f4-583f-4a98-b26c-9d651b2f8918">
<dsig:SignatureProperty Target="data_signature">
<PROP_Sig xmlns="http://ns.adobe.com/pdf/2006" type="cabinet">
<M type="text">D:20151130163741+0100</M>
<Name type="text">CN=<CN>,L=<City>,O=<Organization>,C=<Country></Name>
</PROP_Sig>
</dsig:SignatureProperty>
</dsig:SignatureProperties>
</dsig:Object>
</dsig:Signature>
</sac:SignatureInformation>
</sig:UBLDocumentSignatures>
</ext:ExtensionContent>
</ext:UBLExtension>
</ext:UBLExtensions>
I don't understand why validation says reference[0] fails (the one which referes to element with id), but reference to whole document passes?
#formatc I don´t have privileges to comment, but can you try and view the hexadecimal values in both files (sign and deserialized). I had the same problem, for some reason in my case when constructing back the xml some non-visual characters are inserted in front of the document. You won´t see them unless you use HexView or some tool like that.
I was able to remove those characters programmatically and all went well.
Be sure their array character longs for the case are they equal? before the validation you must see some differencies.
Also, some Signture technics can use any inner sign prefixes like a GUID, control them.
Use Utf8 on both
i had exactly the same issue as you have. signature was valid but references not. the problem is (at least in my case), that serialization and deserialization can affect the content of the xml. in my case it helped to call document.normalizeDocument() before signing the document and now the signature validates even after serialization/deserialization.
In my case it was the difference in the header value which is why it was failing.
The original xml document has
and when it was written header was changed to
Which is why signature verification was failing.
Hence, remove xml declaration while parsing the doc and while writing the doc.
I'm working on a bit of a project for my own amusement that involves outputting the contents of several variables to an XML file. However, when I put the program, the transformer only outputs the first line (the XML header) and nothing else. The saveData() method is called before writeFile(), and I've outputted the value of the variables to the console before calling writeFile() so I know they have a value.
Code below:
public class Output {
private static double citySizeMiles;
private static double citySizeAcres;
private CityType type;
private static int gpLimit;
private static long totalWealth;
private static long cityPopulation;
public static void saveData() {
cityPopulation = CityGenerator.cityPop;
citySizeMiles = City.getCitySizeMiles(cityPopulation);
citySizeAcres = City.getCitySizeAcres(cityPopulation);
gpLimit = City.getGoldLimit();
totalWealth = CityGenerator.cityWealth;
}
public static void writefile() {
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = docFactory.newDocumentBuilder();
// Root Elements
Document doc = builder.newDocument();
Element root = doc.createElement("data");
// Data Element
Element data = doc.createElement("City");
root.appendChild(data);
Attr attr = doc.createAttribute("name");
attr.setValue("Test");
data.setAttributeNode(attr);
// City size (sq miles)
Element sizeMi = doc.createElement("sizeMiles");
sizeMi.appendChild(doc.createTextNode(String.valueOf(citySizeMiles)));
data.appendChild(sizeMi);
// City size (acres)
Element sizeAc = doc.createElement("sizeAcres");
sizeAc.appendChild(doc.createTextNode(String.valueOf(citySizeAcres)));
data.appendChild(sizeAc);
// Population
Element pop = doc.createElement("population");
pop.appendChild(doc.createTextNode(String.valueOf(cityPopulation)));
data.appendChild(pop);
// GP limit
Element gpLim = doc.createElement("gpLimit");
gpLim.appendChild(doc.createTextNode(String.valueOf(gpLimit)));
data.appendChild(gpLim);
// Total fluid wealth
Element wealth = doc.createElement("totalWealth");
wealth.appendChild(doc.createTextNode(String.valueOf(totalWealth)));
data.appendChild(wealth);
// Write to XML file
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", 4);
Transformer trans = tf.newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.setOutputProperty(OutputKeys.METHOD, "xml");
DOMSource source = new DOMSource(doc);
//StreamResult result = new StreamResult(new File("D:\\test.xml"));
StreamResult result = new StreamResult(System.out);
trans.transform(source, result);
} catch(ParserConfigurationException pce) {
pce.printStackTrace();
} catch(TransformerException tfe) {
tfe.printStackTrace();
}
}
}
I'm no expert on DOM (I avoid it like the plague, and encourage everyone else to do likewise) but I think you have failed to connect the root element to the document node.
I was working on a Java Application and I have to map lots of data then generate an XML output.
All the output Looks good, except this 1 random element. As you can see in the image below all the "Value" tags look good, except the 1 highlighted.
http://i.stack.imgur.com/3TgIG.png
Code used to generate XML:
private void generateXML() {
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
doc = docBuilder.newDocument();
//Add Root Element
Element rootElement = doc.createElement("Request");
rootElement.setAttribute("request_id", requestID);
doc.appendChild(rootElement);
//Add Experiment Element
Element experimentElement = doc.createElement("Experiment");
experimentElement.setAttribute("name", mappedData.getFileName()); //Change to experiment name
experimentElement.setAttribute("insert_method", "Insert");
experimentElement.setAttribute("notebook", "BioELN");
experimentElement.setAttribute("researcher", webFormPostData.get("Researchers")[0]);
experimentElement.setAttribute("project", getExcelTypeData.get("project"));
experimentElement.setAttribute("comments", webFormPostData.get("comments")[0]);
experimentElement.setAttribute("expt_date", getCurrentDate());
experimentElement.setAttribute("protocol_name", getExcelTypeData.get("protocolName"));
experimentElement.setAttribute("protocol_version", getExcelTypeData.get("protocolVersion"));
rootElement.appendChild(experimentElement);
//Add Data to Experiment
List<Element> experimentDataElements = generateExperimentDataElements();
for(Element dataElement : experimentDataElements) {
experimentElement.appendChild(dataElement);
}
Element attachmentElement = doc.createElement("Attachment");
attachmentElement.setAttribute("filename", mappedData.getFilePath());
experimentElement.appendChild(attachmentElement);
} catch(Exception e) {
logger.log("Error: " + e);
e.printStackTrace();
}
}
private List<Element> generateExperimentDataElements() {
//Loop through output_mapping mapped data and see if values are found in the mappedData.getMappedData();
List<Element> dataElements = new ArrayList<Element>();
for(int i=0; i < mappedData.getMappedData().size(); i++) { //Cycle Through all Mapped Data Rows
for(Map.Entry<String, Map<String, String>> entry : outputMappedFields.entrySet()) { //Get Required Fields
Element itemElement, valueElement, dataElement;
String mappedVarName = entry.getKey();
String vName = entry.getValue().get("variableName");
String variableType = entry.getValue().get("variableType");
itemElement = doc.createElement("VGItem");
itemElement.setAttribute("row_id", String.valueOf(i+1));
itemElement.setAttribute("table_name", "Results");
itemElement.setAttribute("variable_name", vName);
itemElement.setAttribute("parent_table_name", "Plate");
itemElement.setAttribute("parent_row_id", "plate");
valueElement = doc.createElement("Value");
dataElement = doc.createElement(variableType+"_value");
if(mappedData.getMappedData().get(i).containsKey(mappedVarName)) {
dataElement.setTextContent(mappedData.getMappedData().get(i).get(mappedVarName)); //Get field from Mapped Data
}
valueElement.appendChild(dataElement);
itemElement.appendChild(valueElement);
dataElements.add(itemElement);
}
}
return dataElements;
}
#Override
public String toString() {
try {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(writer));
String output = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + writer.getBuffer().toString().replaceAll("\n|\r", "");
return output;
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
XML FILE: http://paste.strictfp.com/38339
Here is my xml code...
<flow>
<TaskID>100</TaskID>
<TaskID>101</TaskID>
<TaskID>102</TaskID>
<TaskID>103</TaskID>
</flow>
I want to know how to get taskID values in a for loop in java. Please help me...
DOM parser solution, fairly simple, no extra libraries required.
public static void main(String[] args) throws SAXException, IOException,
ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
String input = "<outer>";
input += "<otherstuff><TaskID>123</TaskID></otherstuff>";
input += "<flow>";
input += "<TaskID>100</TaskID>";
input += "<TaskID>101</TaskID>";
input += "<TaskID>102</TaskID>";
input += "<TaskID>103</TaskID>";
input += "</flow>";
input += "</outer>";
Document document = builder.parse(new InputSource(new StringReader(
input)));
NodeList flowList = document.getElementsByTagName("flow");
for (int i = 0; i < flowList.getLength(); i++) {
NodeList childList = flowList.item(i).getChildNodes();
for (int j = 0; j < childList.getLength(); j++) {
Node childNode = childList.item(j);
if ("TaskID".equals(childNode.getNodeName())) {
System.out.println(childList.item(j).getTextContent()
.trim());
}
}
}
}
You'd need to use a FileReader instead if your input came from a file.
Document document = builder.parse(new InputSource(new FileReader(
new File("foo.xml"))));
An alternative to getElementsByTagName() is XPath, a query language for XML, this is particularly useful if you have complicated set of conditions to match.
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("//flow/TaskID/text()");
Object result = expr.evaluate(document, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getTextContent());
}
If your XML file is large, like 100s of MB / GB or you're on a low memory platform then consider a SAX parser.
String input = "<flow><TaskID>100</TaskID><TaskID>101</TaskID><TaskID>102</TaskID><TaskID>103</TaskID></flow>";
SAXParser sax = SAXParserFactory.newInstance().newSAXParser();
DefaultHandler handler = new DefaultHandler() {
private StringBuilder buffer = new StringBuilder();
#Override
public void endElement(String uri, String localName, String qName)
throws SAXException {
if ("TaskID".equals(qName)) {
System.out.println(buffer);
buffer = new StringBuilder();
}
}
#Override
public void characters(char[] ch, int start, int length)
throws SAXException {
buffer.append(ch, start, length);
}
#Override
public void startElement(String uri, String localName,
String qName, Attributes attributes) throws SAXException {
buffer = new StringBuilder();
}
};
sax.parse(new InputSource(new StringReader(input)), handler);
Here's an example using JDOM, which provides a more pleasant API over existing Java XML parsers:
import java.io.File;
import org.jdom2.*;
import org.jdom2.input.*;
public class Test {
// TODO: More appropriate exception handling :)
public static void main (String[] args) throws Exception {
SAXBuilder builder = new SAXBuilder();
Document doc = builder.build(new File("test.xml"));
Element root = doc.getRootElement();
for (Element element : root.getChildren("TaskID")) {
System.out.println(element.getText());
}
}
}
Of course, this assumes that the XML document is small enough to be loaded into memory.
(Obviously you can use the built-in libraries too, and if you're not doing much XML work then that would be fine - I just find them a bit primitive if you're doing any significant amount of work.)
With xpath Here is more information:
http://www.vogella.com/articles/JavaXML/article.html
I personally use JDOM library for all my XML manipulation.. Below is how I would do it;
String xml = "<flow> " +
"<TaskID>100</TaskID>" +
"<TaskID>101</TaskID>" +
"<TaskID>102</TaskID>" +
"<TaskID>103</TaskID>" +
"</flow>";
org.jdom.Document doc = new SAXBuilder().build(new StringReader(xml));
org.jdom.Element rootElement = doc.getRootElement();
List<Element> eles = rootElement.getChildren("TaskID");
for(Element el : eles)
System.out.println(el.getName()+" : "+el.getValue());
You can get it's documentation here: http://www.jdom.org/
Read Xml Children with SAX
<?xml version="1.0"?>
<Patriarch>
<name>Bill</name>
<wife>
<name>Vi</name>
</wife>
<son>
<name>Bill</name>
</son>
<daughter>
<name>Jeri</name>
<husband>
<name>Mark</name>
</husband>
<son>
<name>Greg</name>
</son>
<son>
<name>Tim</name>
</son>
<son>
<name>Mark</name>
</son>
<son>
<name>Josh</name>
<wife>
<name>Kristine</name>
</wife>
<son>
<name>Blake</name>
</son>
<daughter>
<name>Liah</name>
</daughter>
</son>
</daughter>
</Patriarch>
And Java code:
public class ParseXmlSAX {
public static void main(String[] args) {
new ParseXmlSAX("file.xml");
}
public ParseXmlSAX(final String file) {
try {
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
DefaultHandler handler = new DefaultHandler() {
String key = null;
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (key == null)
key = "|";
else
key += qName + "|";
}
public void endElement(String uri, String localName, String qName) throws SAXException {
if (!key.equals("|"))
key = key.substring(0, key.lastIndexOf(qName));
}
public void characters(char ch[], int start, int length) throws SAXException {
String conteudo = new String(ch, start, length).trim();
if (!conteudo.isEmpty()) {
System.out.println(key + " = " + conteudo);
}
}
};
saxParser.parse(this.getClass().getResourceAsStream(file), handler);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class Modifier {
public void modifyXML() {
String strSrcFile = "E:\\projects\\input\\sample.xml";
String strOutputFile = "E:\\projects\\output\\sample.xml";
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(strSrcFile);
Node company = doc.getFirstChild();
System.out.println(company.hasChildNodes());
NodeList nl = company.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
// System.out.println("inner node::"+node.getNodeName());
if (node.hasChildNodes()) {
System.out.println("outer node::" + node.getNodeName());
readChildNodes(node);
} else {
}
}
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(strOutputFile));
transformer.transform(source, result);
} catch (Exception ee) {
ee.printStackTrace();
}
// Get the root element
}
public void readChildNodes(Node node)
{
NodeList nl = node.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node innernode = nl.item(i);
//System.out.println("mediam stage node::"+innernode.getNodeName());
if (innernode.hasChildNodes()) {
System.out.println("inner node::"+innernode.getNodeName());
readChildNodes(innernode);
}
else{
System.out.println("node dont have childs node::"+innernode.getNodeName());
}
}
}
public void replaceGraphicCode(Node innernode) {
NamedNodeMap attr = innernode.getAttributes();
Node nodeAttr = attr.getNamedItem("id");
String IDvalue = nodeAttr.getTextContent();
// nodeAttr.setTextContent("2");
}
public void replaceOriginator(Node innernode) {
NamedNodeMap attr = innernode.getAttributes();
Node nodeAttr = attr.getNamedItem("enterpriseCode");
}
public static void main(String[] args) {
Modifier objModifier = new Modifier();
objModifier.modifyXML();
}
}
I am reading an XML file using Stax parser and writing it using DOM in java. I am not getting desired XML output. I read following XML file
<config>
<Sensor1>
<name>abc</name>
<range>100</range>
</Sensor1>
<sensor2>
<name>xyz</name>
<range>100</range>
</sensor2>
</config>
I parse the above XML file using Stax parser as follows
public void readConfig(String configFile) {
boolean sensor1 = false;
boolean sensor2 = false;
try
{
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
InputStream in = new FileInputStream(configFile);
XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
// Read the XML document
while (eventReader.hasNext()) {
XMLEvent event = eventReader.nextEvent();
if (event.isStartElement()) {
StartElement startElement = event.asStartElement();
if (startElement.getName().getLocalPart() == (sensor1)) {
sensor1 = true;
Sensor1 Obj1 = new Sensor1();
}
if (startElement.getName().getLocalPart() == (sensor2)) {
sensor2 = true;
Sensor2 Obj2 = new Sensor2();
}
if (sensor1) {
if (event.asStartElement().getName().getLocalPart().equals(name)) {
event = eventReader.nextEvent();
Obj1.set_Sensor_Name(event.asCharacters().getData());
continue;
}
if (event.asStartElement().getName().getLocalPart().equals(range)) {
event = eventReader.nextEvent();
Obj1.set_Sensor_Range(event.asCharacters().getData());
continue;
}
}
if (sensor2) {
if (event.asStartElement().getName().getLocalPart().equals(name)) {
event = eventReader.nextEvent();
Obj2.set_Sensor_Name(event.asCharacters().getData());
continue;
}
if (event.asStartElement().getName().getLocalPart().equals(range)) {
event = eventReader.nextEvent();
Obj1.set_Sensor_Range(event.asCharacters().getData());
continue;
}
}
if (event.isEndElement()) {
EndElement endElement = event.asEndElement();
if (endElement.getName().getLocalPart() == (sensor1)) {
sensor1.addToArray();
}
if (endElement.getName().getLocalPart() == (sensor2)) {
sensor2.addToArray();
}
}
}
In "Sensor1" and "Sensor2" class I am adding extra information depending on some condition.
class Sensor1 {
public ArrayList<Object> list = new ArrayList<Object>();
String name;
double range;
public void set_Sensor_Name(String name) {
this.name = name;
}
public void set_Sensor_Range(double range) {
this.range = range;
}
public void addToArray(){
double distance =50;
if(distance<range){
list.add("TITANIC");
list.add(123456);
}
WriteFile fileObj = new WriteFile();
fileObj.writeXMlFile(list);
}
}
This is the class to write the XML
public class WriteFile {
public void writeXmlFile(ArrayList<Object> list) {
try {
DocumentBuilderFactory dFact = DocumentBuilderFactory.newInstance();
DocumentBuilder build = dFact.newDocumentBuilder();
Document doc = build.newDocument();
Element root = doc.createElement("SensorTracks");
doc.appendChild(root);
Element sensorInfo = doc.createElement("SensorDetails");
root.appendChild(sensorInfo);
Element vesselInfo = doc.createElement("VesselDetails");
root.appendChild(vesselInfo);
for(int i=0; i<list.size(); i +=4 ) {
Element name = doc.createElement("SensorName");
name.appendChild(doc.createTextNode(String.valueOf(list.get(i))));
sensorInfo.appendChild(name);
Element range = doc.createElement("SensorRange");
name.appendChild(doc.createTextNode(String.valueOf(list.get(i+1))));
sensorInfo.appendChild(range);
Element mmi = doc.createElement("shipname");
mmi.appendChild(doc.createTextNode(String.valueOf(list.get(i+2))));
vesselInfo.appendChild(mmi);
Element license = doc.createElement("license");
license.appendChild(doc.createTextNode(String.valueOf(list.get(i+3))));
vesselInfo.appendChild(license);
}
// Save the document to the disk file
TransformerFactory tranFactory = TransformerFactory.newInstance();
Transformer aTransformer = tranFactory.newTransformer();
// format the XML nicely
aTransformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1");
aTransformer.setOutputProperty(
"{http://xml.apache.org/xslt}indent-amount", "4");
aTransformer.setOutputProperty(OutputKeys.INDENT, "yes");
DOMSource source = new DOMSource(doc);
try {
FileWriter fos = new FileWriter("/home/ros.xml");
StreamResult result = new StreamResult(fos);
aTransformer.transform(source, result);
} catch (IOException e) {
e.printStackTrace();
}
} catch (TransformerException ex) {
System.out.println("Error outputting document");
} catch (ParserConfigurationException ex) {
System.out.println("Error building document");
}
When I execute, I get following XML
<SensorTracks>
<sensorDetails>
<SensorName>xyz</SensorName>
<SensorRange>100</SensorRange>
</sensorDetails>
<VesselDetails>
<shipname>TITANIC</shipname>
<license>123456</license>
</vesselDetails>
MY FINAL OUTPUT MUST BE
<config>
<SensorTracks>
<sensorDetails>
<SensorName>xyz</SensorName>
<SensorRange>100</SensorRange>
<SensorName>abc</SensorName>
<SensorRange>100</SensorRange>
</sensorDetails>
<VesselDetails>
<shipname>TITANIC</shipname>
<license>123456</license>
</vesselDetails>
What wrong thing I am I doing in my code ?? Any help is appreciated. Thanks in advance
I am answering my own question again. The problem is very simple. To get the desired output as mention above. just make the following changes to "WriteFile" class.
FileWriter fos = new FileWriter("/home/ros.xml" ,true);
Finally, I am learning Java :)
Frankly speaking the example looks cumbersome. Do you consider to use apache digester of jaxb?
http://commons.apache.org/digester/
http://www.oracle.com/technetwork/articles/javase/index-140168.html