Xml document signature not valid after deserialization from byte array - java

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.

Related

How to get hash from XML for signing in java

I have to create an application which has XML data and creates Hash for signing and send the hash to an API to get the raw signature for XML and append signature for XML in Java How can I achieve this.
The same thing can be done in .Net by overriding SignedXml class like this
public class CustomSignedXml: SignedXml
{
public CustomSignedXml(XmlDocument xmlDoc) : base(xmlDoc)
{
}
public void ComputeSignature()
{
CryptoConfig.AddAlgorithm(typeof(RSAPKCS1SHA256SignatureDescription), "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
MethodInfo methodInfo = typeof(SignedXml).GetMethod("BuildDigestedReferences", BindingFlags.Instance | BindingFlags.NonPublic);
methodInfo.Invoke(this, null);
SignedInfo.SignatureMethod = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
SignatureDescription signatureDescription = CryptoConfig.CreateFromName(SignedInfo.SignatureMethod) as SignatureDescription;
if (signatureDescription == null)
throw new CryptographicException("Cryptography_Xml_SignatureDescriptionNotCreated");
HashAlgorithm hashAlg = signatureDescription.CreateDigest();
if (hashAlg == null)
throw new CryptographicException("Cryptography_Xml_CreateHashAlgorithmFailed");
MethodInfo methodInfo2 = typeof(SignedXml).GetMethod("GetC14NDigest", BindingFlags.Instance | BindingFlags.NonPublic);
byte[] hashvalue = (byte[])methodInfo2.Invoke(this, new object[] { hashAlg });
var signature = GetSignatureFromServer(hashvalue);
m_signature.SignatureValue = signature;
}
}
And use CustomSignedXml class to sign using following meathod
public string GetSignedXml(string xmlDoc, X509Certificate2 PublicCertificate)
{
try
{
XmlDocument xmlDocumentToSign = new XmlDocument();
xmlDocumentToSign.LoadXml(xmlDoc);
CustomSignedXml signedXml = new CustomSignedXml(xmlDocumentToSign);
Reference reference = new Reference();
reference.Uri = "";
reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
reference.AddTransform(new XmlDsigExcC14NTransform());
reference.DigestMethod = "http://www.w3.org/2001/04/xmlenc#sha256";
signedXml.AddReference(reference);
signedXml.ComputeSignature();
KeyInfo keyInfo = new KeyInfo();
keyInfo.AddClause(GetKeyInfoData(PublicCertificate));
signedXml.KeyInfo = keyInfo;
var xmlDigitalSignature = signedXml.GetXml();
xmlDocumentToSign.DocumentElement.AppendChild(xmlDocumentToSign.ImportNode(xmlDigitalSignature, true));
return xmlDocumentToSign.OuterXml;
}
catch (Exception)
{
throw;
}
}
How can I do the same in JAVA

How to Print String object Line by Line

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.

doc.createElement() forgot the opening "<"

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

Reading and writing an xml in java

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

xml parsing+Java ME

I am editing my qestion to make clear idea about the string name resfile_name and result
I want to do xml parsing.where i am passing some parameter to url ane it gives me responce in xml format which i take it in string name result now i want to parse that string(xml data).
i am using the follwing below code:-
SAXParserFactory factory = SAXParserFactory.newInstance();
SAXParser saxParser = factory.newSAXParser();
vector = new Vector();
vector.addElement(new KeyPair("ParentID", "10000186"));
String result = Constants.callSoap("GetChildList", vector);
InputStream is = new ByteArrayInputStream(result.getBytes("UTF-8"));
Reader reader = new InputStreamReader(in);
XmlParser parser = new XmlParser(reader);
ParseEvent pe = null;
Reader reader = new InputStreamReader(in);
XmlParser parser = new XmlParser(reader);
ParseEvent pe = null;
parser.skip();
parser.read(Xml.START_TAG, null, "GetChildListResult");
parser.skip();
parser.read(Xml.START_TAG, null, "CustomChildList");
boolean trucking = true;
boolean first = true;
while (trucking) {
pe = parser.read();
if (pe.getType() == Xml.START_TAG) {
String name = pe.getName();
System.out.println("nAME=="+name);
if (name.equals("ChildID")) {
String title, link, description;
title = link = description = null;
while ((pe.getType() != Xml.END_TAG) ||
(pe.getName().equals(name) == false)) {
pe = parser.read();
if (pe.getType() == Xml.START_TAG &&
pe.getName().equals("ChildName")) {
pe = parser.read();
title = pe.getText();
}
else if (pe.getType() == Xml.START_TAG &&
pe.getName().equals("IMEINumber")) {
pe = parser.read();
link = pe.getText();
}
else if (pe.getType() == Xml.START_TAG &&
pe.getName().equals("ChildStatus")) {
pe = parser.read();
description = pe.getText();
}
}
}
else {
while ((pe.getType() != Xml.END_TAG) ||
(pe.getName().equals(name) == false))
pe = parser.read();
}
}
if (pe.getType() == Xml.END_TAG &&
pe.getName().equals("GetChildListResult"))
trucking = false;
}
the Constants.callSoap("GetChildList", vector); calls the callsoap method in constants which has code:--
public static String callSoap(String method, Vector vector) {
String result = null;
Constants.log("callSoap");
try {
SoapObject request = new SoapObject(NAMESPACE, method);
if (vector != null) {
for (int i = 0; i < vector.size(); i++) {
KeyPair keyPair = (KeyPair) vector.elementAt(i);
request.addProperty(keyPair.getKey(), keyPair.getValue());
}
}
Constants.log("callSoap2");
Element[] header = new Element[1];
header[0] = new Element().createElement(NAMESPACE, "AuthSoapHd");
Element username = new Element().createElement(NAMESPACE, "strUserName");
username.addChild(Node.TEXT, "*****");
header[0].addChild(Node.ELEMENT, username);
Element password = new Element().createElement(NAMESPACE, "strPassword");
password.addChild(Node.TEXT, "******");
header[0].addChild(Node.ELEMENT, password);
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
envelope.dotNet = true;
envelope.headerOut = header;
envelope.setOutputSoapObject(request);
Constants.log("callSoap3");
HttpTransport transport = new HttpTransport("http://***.***.*.***/ChildTrackerService/ChildTrackerService.asmx?wsdl");
//log("Log:transport");
transport.setXmlVersionTag("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
//log("Log:transport1");
try {
transport.call("http://tempuri.org/" + method, envelope);
//log("Log:transport:call");
result = (envelope.getResponse()).toString();
} catch (Exception e) {
System.out.println("exception of IP==" + e);
}
} catch (Exception e) {
log("Exception CallSoap:" + e.toString());
}
return result;
}
And the class keypair contain:-
public KeyPair(String key, String value) {
this.key = key;
this.value = value;
}
public String getKey() {
return key;
}
public String getValue() {
return value;
}
The string reult has --
result==anyType{CustomChildList=anyType{ChildID=452; ChildName=Local; IMEINumber=958694; ChildStatus=Free; ExpiryDate=2011-05-26T16:22:21.29; RemainigDays=1; SOS=1; }; CustomChildList=anyType{ChildID=502; ChildName=testing; IMEINumber=123456; ChildStatus=anyType{}; ExpiryDate=null; RemainigDays=0; SOS=1; }; CustomChildList=anyType{ChildID=523; ChildName=abc; IMEINumber=124124; ChildStatus=anyType{}; ExpiryDate=null; RemainigDays=0; SOS=1; }; }
the actual response is like this:--
452
Local
958694
Free
2011-05-26T16:22:21.29
1
1
502
testing
123456
0
1
523
abc
124124
0
1
Following code will look for resources in classpath with the name passed in argument and you are passing whole XML so NPE is obvious.
this.getClass().getResourceAsStream(resfile_name)
You better get the inputStream from URL , as shown in below broken snippet and move ahead
HttpConnection hc = null;
try {
hc = (HttpConnection)Connector.open(url);
parse(hc.openInputStream());
See
Parsing XML in java-me

Categories

Resources