I need to sign a specific XML tag with java 1.6. My XML is like this:
<RecepcionarLoteRps>
<EnviarLoteRpsEnvio xmlns="http://isscuritiba.curitiba.pr.gov.br/iss/nfse.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://isscuritiba.curitiba.pr.gov.br/iss/nfse.xsd">
<LoteRps>
<ListaRps>
<Rps>
<InfRps id="1">
. . .
</InfRps>
</Rps>
</ListaRps>
</EnviarLoteRpsEnvio>
My java code to sign it (excluding the keystore part) is:
try {
String ArqAssinar = "file.xml";
String Charset = "UTF-8";
/* URI and ID */
String idRef = "1";
String uriRef = "#" + idRef;
XMLSignatureFactory XmlSignFac = XMLSignatureFactory.getInstance("DOM");
DigestMethod DigMet = XmlSignFac.newDigestMethod(DigestMethod.SHA1, null);
Transform TransfRef1 = XmlSignFac.newTransform(CanonicalizationMethod.INCLUSIVE, (TransformParameterSpec) null);
Transform TransfRef2 = XmlSignFac.newTransform(SignatureMethod.RSA_SHA1, (C14NMethodParameterSpec) null);
List<Transform> Transfs = new ArrayList<Transform>();
Transfs.add(TransfRef1);
Transfs.add(TransfRef2);
/* Reference - where I use URI and ID */
Reference Ref = XmlSignFac.newReference(uriRef, DigMet, Transfs, null, idRef);
CanonicalizationMethod CannMet = XmlSignFac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null);
SignatureMethod SignMet = XmlSignFac.newSignatureMethod(SignatureMethod.RSA_SHA1, null);
/* SignedInfo - where I use Reference */
SignedInfo SignInfo = XmlSignFac.newSignedInfo(CannMet, SignMet, Collections.singletonList(Ref));
KeyInfoFactory keyInfFac = XmlSignFac.getKeyInfoFactory();
List<X509Certificate> X509Content = new ArrayList<X509Certificate>();
X509Content.add(Certif);
X509Data X509dados = keyInfFac.newX509Data(X509Content);
KeyInfo KeyInf = keyInfFac.newKeyInfo(Collections.singletonList(X509dados));
/* Process file for input */
DocumentBuilderFactory DocBuilderFactory = DocumentBuilderFactory.newInstance();
DocBuilderFactory.setNamespaceAware(true);
DocumentBuilder DocBuilder = DocBuilderFactory.newDocumentBuilder();
InputStream Input = new FileInputStream(arq);
Reader Leitor = new InputStreamReader(Input, Charset);
InputSource Origem = new InputSource(Leitor);
Document Doc = DocBuilder.parse(Origem);
/* Search for tag in document using ID */
XPathFactory factory = XPathFactory.newInstance();
XPath xpathPesquisa = factory.newXPath();
XPathExpression expr = xpathPesquisa.compile(String.format("//*[#id='%s']", idRef));
NodeList nodes = (NodeList) expr.evaluate(docParaAssinar, XPathConstants.NODESET);
Node Tag = null;
DOMSignContext DocSignCont = null;
XMLSignature Signature = null;
if (nodes.getLength() != 0) {
tagComId = nodes.item(0);
Tag = tagComId.getParentNode();
DocSignCont = new DOMSignContext(PrivPass, Tag);
/* Do the signature */
Signature = this.XmlSignFac.newXMLSignature(SignInfo, KeyInf);
Signature.sign(DocSignCont);
/* Updates the file */
OutputStream Saida = new FileOutputStream(arqAtualizar);
Writer Escritor = new OutputStreamWriter(Saida, Charset);
StreamResult Resultado = new StreamResult(Escritor);
TransformerFactory TransformFac = TransformerFactory.newInstance();
Transformer Transf = TransformFac.newTransformer();
Transf.transform(new DOMSource(docAssinado), Resultado);
} else {
. . .
}
} catch (Exception E) {
. . .
}
When I run this code in Eclipse I get a StackOverflow error inside the DOMXMLSignature.sign() method. There is a call for the DOMXMLSignature.digestReference() method, and the function calls itself indefinitely.
This code works if the URI is "" and ID is null, that is, when I need to sign the entire XML.
What do I need to do differently to get sign a specific XML tag?
I have had some problems with this code:
public final class DOMXMLSignature extends DOMStructure
implements XMLSignature {
#Override
public void sign(XMLSignContext signContext)
throws MarshalException, XMLSignatureException
{
if (signContext == null) {
throw new NullPointerException("signContext cannot be null");
}
DOMSignContext context = (DOMSignContext)signContext;
marshal(context.getParent(), context.getNextSibling(),
DOMUtils.getSignaturePrefix(context), context);
// generate references and signature value
List<Reference> allReferences = new ArrayList<>();
// traverse the Signature and register all objects with IDs that
// may contain References
signatureIdMap = new HashMap<>();
signatureIdMap.put(id, this);
signatureIdMap.put(si.getId(), si);
#SuppressWarnings("unchecked")
List<Reference> refs = si.getReferences();
for (Reference ref : refs) {
signatureIdMap.put(ref.getId(), ref);
}
for (XMLObject obj : objects) {
signatureIdMap.put(obj.getId(), obj);
#SuppressWarnings("unchecked")
List<XMLStructure> content = obj.getContent();
for (XMLStructure xs : content) {
if (xs instanceof Manifest) {
Manifest man = (Manifest)xs;
signatureIdMap.put(man.getId(), man);
#SuppressWarnings("unchecked")
List<Reference> manRefs = man.getReferences();
for (Reference ref : manRefs) {
allReferences.add(ref);
signatureIdMap.put(ref.getId(), ref);
}
}
}
}
// always add SignedInfo references after Manifest references so
// that Manifest reference are digested first
allReferences.addAll(refs);
// generate/digest each reference
for (Reference ref : allReferences) {
digestReference((DOMReference)ref, signContext);
}
// do final sweep to digest any references that were skipped or missed
for (Reference ref : allReferences) {
if (((DOMReference)ref).isDigested()) {
continue;
}
((DOMReference)ref).digest(signContext);
}
Key signingKey = null;
try {
KeySelectorResult keySelectorResult = signContext.getKeySelector().select(ki,
KeySelector.Purpose.SIGN,
si.getSignatureMethod(),
signContext);
signingKey = keySelectorResult.getKey();
if (signingKey == null) {
throw new XMLSignatureException("the keySelector did not " +
"find a signing key");
}
ksr = keySelectorResult;
} catch (KeySelectorException kse) {
throw new XMLSignatureException("cannot find signing key", kse);
}
// calculate signature value
try {
byte[] val = ((AbstractDOMSignatureMethod)
si.getSignatureMethod()).sign(signingKey, si, signContext);
((DOMSignatureValue)sv).setValue(val);
} catch (InvalidKeyException ike) {
throw new XMLSignatureException(ike);
}
this.localSigElem = sigElem;
}
private void digestReference(DOMReference ref, XMLSignContext signContext)
throws XMLSignatureException
{
if (ref.isDigested()) {
return;
}
// check dependencies
String uri = ref.getURI();
if (Utils.sameDocumentURI(uri)) {
String parsedId = Utils.parseIdFromSameDocumentURI(uri);
if (parsedId != null && signatureIdMap.containsKey(parsedId)) {
XMLStructure xs = signatureIdMap.get(parsedId);
if (xs instanceof DOMReference) {
digestReference((DOMReference)xs, signContext);
} else if (xs instanceof Manifest) {
Manifest man = (Manifest)xs;
List<Reference> manRefs = DOMManifest.getManifestReferences(man);
for (int i = 0, size = manRefs.size(); i < size; i++) {
digestReference((DOMReference)manRefs.get(i),
signContext);
}
}
}
// if uri="" and there are XPath Transforms, there may be
// reference dependencies in the XPath Transform - so be on
// the safe side, and skip and do at end in the final sweep
if (uri.length() == 0) {
List<Transform> transforms = ref.getTransforms();
for (Transform transform : transforms) {
String transformAlg = transform.getAlgorithm();
if (transformAlg.equals(Transform.XPATH) ||
transformAlg.equals(Transform.XPATH2)) {
return;
}
}
}
}
ref.digest(signContext);
}
}
public final class Utils {
/**
* Returns the ID from a same-document URI (ex: "#id")
*/
public static String parseIdFromSameDocumentURI(String uri) {
if (uri.length() == 0) {
return null;
}
String id = uri.substring(1);
if (id != null && id.startsWith("xpointer(id(")) {
int i1 = id.indexOf('\'');
int i2 = id.indexOf('\'', i1+1);
id = id.substring(i1+1, i2);
}
return id;
}
/**
* Returns true if uri is a same-document URI, false otherwise.
*/
public static boolean sameDocumentURI(String uri) {
return uri != null && (uri.length() == 0 || uri.charAt(0) == '#');
}
}
This is just a piece of the DOMXMLSignature class and the Util class, just the methods that matter to the case.
My code above class the DOMXMLSignature.sign() method. This method do the marshall, get the reference, get the reference id, the call DOMXMLSignature.digestReference() method.
The DOMXMLSignature.digestReference() method verify if the reference is alredy digested - it is not. So he get the URI, verifies if this is a same-document URI - it is - , confiorms that the id in document is the id in URI. Then, the problem: the instance obtainded with signatureIdMap.get(parsedId) is ALWAYS of the type DOMReference, so the method calls yourself indefinitely.
This was happening in the java 1.6, in native class with no change. How can I solve this problem and sign a specific XML tag? Will I have to calclulate the digestvalue before call the DOMXMLSignature.sign() method?
Wow.
First, your code is not a reproducible example:
tagComId docParaAssinar docAssinado are not declared, and the latter two never set. I added the type Node for the first and replaced the latter two by Doc. FYI: using initial caps for names of locals (also fields or methods) is against conventional style and thus feels weird, but does work, so I didn't bother changing these.
SignatureMethod.RSA_SHA1 is not a valid Transform and trying to use it as one throws an exception. It also doesn't make sense to be in the Transforms list of a Reference, because signature is not applied separately to one Reference, but to the SignedInfo which includes potentially multiple References plus other data. I removed it.
in addition for more convenient testing I replaced the file I/O (which looked okay) with canned input and console output.
With these changes I do reproduce the stackoverflow. This is because you specified #1 as the URI and 1 as the id of the Reference, so to resolve the Reference it must goto the referenced element and resolve it, and the referenced element is itself the (same) Reference so it must go to the identified referenced element and resolve it, so it must etc etc. You must not make the id of the Reference the same as the element you are trying to reference, should not make it the same any other element, and you don't need to refer to the Reference itself so it's better to not set any id for it. I changed the id in newReference to null.
With these changes, it does work for me to sign "" (the whole document) but not "#1". I found that is because #x does NOT refer to (an element with) an attribute named "id", it refers to (one with) an attribute defined in the schema or DTD as an id -- and your <InfRps id="1"> is not defined as an id. See
No working ID attribute when parsing XML in java
Java XML DOM: how are id Attributes special?
Xml id attribute to work with Java's getElementById?
The schema you reference defines this attribute only as a string not an id, and isn't being used anyway because DOM-parser by default doesn't use schemas. Rather than fiddle with editting and using a schema, I wrote a (very!) minimal DTD to make this attribute an id, and the following code works for me to sign the desired element (using a dummy key&cert I created):
static void SO69652045XMLSign (String[] args) throws Exception {
//++ debug data
String input = "<!DOCTYPE RecepcionarLoteRps [ <!ATTLIST InfRps id ID #REQUIRED> ] >"+
"<RecepcionarLoteRps><EnviarLoteRpsEnvio xmlns=\"http://isscuritiba.curitiba.pr.gov.br/iss/nfse.xsd\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://isscuritiba.curitiba.pr.gov.br/iss/nfse.xsd\">"+
"<LoteRps><ListaRps><Rps><InfRps id=\"1\">xxx</InfRps></Rps></ListaRps> </LoteRps> </EnviarLoteRpsEnvio></RecepcionarLoteRps>";
KeyStore keystore = KeyStore.getInstance("PKCS12");
try(InputStream is = new FileInputStream("69652045.p12")){ keystore.load(is,"sekrit".toCharArray()); }
PrivateKey PrivPass = (PrivateKey) keystore.getKey("mykey","sekrit".toCharArray());
X509Certificate Certif = (X509Certificate) keystore.getCertificateChain("mykey")[0];
//--String ArqAssinar = "file.xml";
//--String Charset = "UTF-8";
/* URI and ID */
String idRef = "1";
String uriRef = "#" + idRef;
XMLSignatureFactory XmlSignFac = XMLSignatureFactory.getInstance("DOM");
DigestMethod DigMet = XmlSignFac.newDigestMethod(DigestMethod.SHA1, null);
Transform TransfRef1 = XmlSignFac.newTransform(CanonicalizationMethod.INCLUSIVE, (TransformParameterSpec) null);
//--Transform TransfRef2 = XmlSignFac.newTransform(SignatureMethod.RSA_SHA1, (C14NMethodParameterSpec) null);
List<Transform> Transfs = new ArrayList<Transform>();
Transfs.add(TransfRef1);
//--Transfs.add(TransfRef2);
/* Reference - where I use URI and ID */
Reference Ref = XmlSignFac.newReference(uriRef, DigMet, Transfs, null, /*idRef*/null);
CanonicalizationMethod CannMet = XmlSignFac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null);
SignatureMethod SignMet = XmlSignFac.newSignatureMethod(SignatureMethod.RSA_SHA1, null);
/* SignedInfo - where I use Reference */
SignedInfo SignInfo = XmlSignFac.newSignedInfo(CannMet, SignMet, Collections.singletonList(Ref));
KeyInfoFactory keyInfFac = XmlSignFac.getKeyInfoFactory();
List<X509Certificate> X509Content = new ArrayList<X509Certificate>();
X509Content.add(Certif);
X509Data X509dados = keyInfFac.newX509Data(X509Content);
KeyInfo KeyInf = keyInfFac.newKeyInfo(Collections.singletonList(X509dados));
/* Process file for input */
DocumentBuilderFactory DocBuilderFactory = DocumentBuilderFactory.newInstance();
DocBuilderFactory.setNamespaceAware(true);
DocumentBuilder DocBuilder = DocBuilderFactory.newDocumentBuilder();
//--InputStream Input = new FileInputStream(arq);
//--Reader Leitor = new InputStreamReader(Input, Charset);
//--InputSource Origem = new InputSource(Leitor);
InputSource Origem = new InputSource (new StringReader (input)); //++
Document Doc = DocBuilder.parse(Origem);
/* Search for tag in document using ID */
XPathFactory factory = XPathFactory.newInstance();
XPath xpathPesquisa = factory.newXPath();
XPathExpression expr = xpathPesquisa.compile(String.format("//*[#id='%s']", idRef));
NodeList nodes = (NodeList) expr.evaluate(/*docParaAssinar*/Doc, XPathConstants.NODESET);
Node Tag = null;
DOMSignContext DocSignCont = null;
XMLSignature Signature = null;
if (nodes.getLength() != 0) {
Node tagComId = nodes.item(0); //**
Tag = tagComId.getParentNode();
DocSignCont = new DOMSignContext(PrivPass, Tag);
/* Do the signature */
Signature = /*this.*/XmlSignFac.newXMLSignature(SignInfo, KeyInf);
Signature.sign(DocSignCont);
/* Updates the file */
//--OutputStream Saida = new FileOutputStream(arqAtualizar);
//--Writer Escritor = new OutputStreamWriter(Saida, Charset);
Writer Escritor = new OutputStreamWriter(System.out,StandardCharsets.UTF_8); //++
StreamResult Resultado = new StreamResult(Escritor);
TransformerFactory TransformFac = TransformerFactory.newInstance();
Transformer Transf = TransformFac.newTransformer();
Transf.transform(new DOMSource(/*docAssinado*/Doc), Resultado);
} else {
throw new Exception ("id not found");
}
}
which produces, lightly edited for clarity:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<RecepcionarLoteRps><EnviarLoteRpsEnvio xmlns="http://isscuritiba.curitiba.pr.gov.br/iss/nfse.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://isscuritiba.curitiba.pr.gov.br/iss/nfse.xsd">
<LoteRps><ListaRps><Rps>
<InfRps id="1">xxx</InfRps>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<Reference URI="#1">
<Transforms><Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/></Transforms>
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<DigestValue>fRXn427d6rObJ0udybG5aY5E6n4=</DigestValue>
</Reference></SignedInfo>
<SignatureValue>...</SignatureValue>
<KeyInfo><X509Data><X509Certificate>...</X509Certificate></X509Data></KeyInfo>
</Signature>
</Rps></ListaRps> </LoteRps> </EnviarLoteRpsEnvio></RecepcionarLoteRps>
Whether this form of defining the XML, or another, is acceptable in your environment or application(s) I cannot say.
Finally, in case you don't know, SHA1 was broken for collision in 2017 and most competent security authorities no longer allow signatures using it (directly or indirectly). (For SSL/TLS certificates including websites like this one SHA1 had already been forbidden since 2014-2015.) But that's offtopic for SO.
I have the XML document of the various types of OPC UA and some custom object types added to it.. for eg((1) StudentType with properties of Age, Birthplace (2) TeacherType with properties of Name, Expertise))
Also, I have another text input which says (XX -- FolderType, AA -- StudentType, BB --TeacherType) Inshort it mentions the instance name and the type of the instance.
This complete thing can be built with UAModeller tool ofcourse, however we plan to write a java program which does this for us automatically when inputs are provided.
To start off, I have taken the types.xml file, and have parsed it. I have created a list of UAObjectTypes, UAVariableTypes, StudentTypes,TeacherTypes etc.
I have made myself a list which maps the inputlist of instances, to their ObjectTypes.
But I am not able to establish the references as expected.
For eg:
Every node in OPC UA is connected to the other via references. For eg: Class is "OrganisedBy" Objects. Class "organises" Students and Teachers. Students "organises" Rakshan and so on.
I am struggling to establish a dynamic production of this address Space via code.
I have the sample address sace produced by the tool. But the java program does not produce the same.
File xmlFile = new File("studteachobjmodel.xml"); //this is the types.xml
JAXBContext jaxbContext;
jaxbContext = JAXBContext.newInstance(UANodeSet.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
UANodeSet xmlentries = (UANodeSet) jaxbUnmarshaller.unmarshal(xmlFile);
entries.add(xmlentries);
//This has to be well known in prior
UANodeSet newUANodeSetObject = new UANodeSet();
List<UAObjectType> objectTypeList = xmlentries.getUAObjectType();
HashMap<String, UAObjectType> mapWithExtractedObjectTypes = new HashMap<String, UAObjectType>();
for(String name: newUniqueList) {
for(UAObjectType o : objectTypeList) {
if(o.getDisplayName().equals(name))
mapWithExtractedObjectTypes.put(o.getDisplayName(), o); //mapping types with their objectTypes
}
}
System.out.println("----------MAPPING DONE---------------------");
List<UAObject> objectList = xmlentries.getUAObject();
List<UAObject> newObjectList = new ArrayList<UAObject>();
UAObject uaObject = null;
List<String> newNameSpaceUris = new ArrayList<String>();
newNameSpaceUris.add("http://yourorganisation.org/trial1/");
newUANodeSetObject.setNamespaceUris(newNameSpaceUris);
List<UAVariable> variableList = new ArrayList<UAVariable>();
for(Map.Entry mapElement:inputMap.entrySet()) {
String key = (String) mapElement.getKey();
String type = inputMap.get(key);
String value = mapWithExtractedObjectTypes.get(type).getNodeId();
UAObjectType tempType =mapWithExtractedObjectTypes.get(type);
// String value = opcuaInternalMap.get(type);
for(UAObjectType o : objectTypeList) {
if (o.getNodeId().equals(value))
{
// System.out.println(o.getReferences());
uaObject = new UAObject();
List<Reference> referencesForObject = new ArrayList<Reference>();
uaObject.setNodeId("ns=1;s="+key);//String.valueOf(min+random.nextInt(upperBound)));
uaObject.setBrowsename("1:"+key);
uaObject.setDisplayName(key);
List<Reference>tempRef=tempType.getReferences();
Reference ref_01= new Reference();
ref_01.setReferenceType("HasTypeDefinition");
ref_01.setReference(value);
//
////////////////////////NEED GUIDANCE HERE//////////////////////////////////
// Reference ref_02= new Reference();
// ref_02.setReferenceType("Organizes");
// ref_02.setReference("i=85");
// referencesForObject.add(ref_01);
// referencesForObject.add(ref_02);
tempRef.add(ref_01);
uaObject.setReferences(tempRef);
break;
}
}
if(uaObject!=null) {
newObjectList.add(uaObject);
}
newUANodeSetObject.setUAObject(newObjectList);
}
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(newUANodeSetObject, new File("Instances.xml"));
}catch (JAXBException e) {
e.printStackTrace();
} catch (FactoryConfigurationError e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Please provide me some guidance. totally clueless as of now.
I'm reading file-Paths from a collection
Collection<String> FileList = new ArrayList<>();
this collection can contain more than 600.000 File-paths, but with my current method it takes up to a few hours, to create the text-file with all information.
Every XML contains a list of -items- which could have a tag -value- with the attribute -value is_special="true"-. In this case, the name of the -item- should be stored. The result looks like:
C:\bar\foo\archive\T16-0B07186E3B194D2341256D2F003FF1FE.xml
C:\bar\foo\archive\C1257FBF0040265C-1\T26-75A218AFA1FC460B41256D9C00406708.xml
C:\bar\foo\archive\C1257FBF0040265C-1\T26-75A218AFA1FC460B41256D9C99406708.xml
Itemname:CreationDate
Itemname:PublishingDate
Itemname:ValidThruDate
Itemname:ArchiveDate
Itemname:ReleaseDate
Itemname:EraseDate
Current function:
public void FullFilterAndExport() throws JAXBException, IOException {
totalFilesCount = 0;
totalFilesCountPositive = 0;
PrintWriter pWriter = new PrintWriter(new BufferedWriter(new FileWriter(DB_Path.toString() + "\\export_full.txt")));
for(String file: FileList) {
if (file.endsWith(".xml") && !file.contains("databaseinfo.xml")) {
totalFilesCount = totalFilesCount +1;
ItemList.clear();
JAXBContext context = JAXBContext.newInstance(NotesDocumentMetaFile.class);
Unmarshaller um = context.createUnmarshaller();
NotesDocumentMetaFile docMetaFile = (NotesDocumentMetaFile) um.unmarshal(new FileReader(file));
for(int i = 0; i < docMetaFile.getItems().size(); i++) {
if(docMetaFile.getItems().get(i).getValueIsSpecial() == true) {
ItemList.add("Itemname:" + docMetaFile.getItems().get(i).getName());
}
}
if(!ItemList.isEmpty()) {
totalFilesCountPositive = totalFilesCountPositive + 1;
pWriter.println(file);
pWriter.println();
for(String item : ItemList) {
pWriter.println(item);
}
pWriter.println();
}
}
}
pWriter.println();
pWriter.println("------------------");
pWriter.println("Anzahl der geprüften Dateien: " + totalFilesCount);
pWriter.println("Anzahl der geprüften positiven Dateien: " + totalFilesCountPositive);
if (pWriter != null){
pWriter.flush();
pWriter.close();
}
Is there any chance to improve the performance?
profile (using jvisualvm, included in oracle jdk), section cpu sampling snapshot.
a culprit might be jaxb. If it is the case try any streaming xml reader. The code will be uglier, but should be faster. Re-test / Re-profile to check what is taking cpu time
you might want to de-correlate reading from xml files and writing to the output text file, using for example a BlockingDeque that will contain the result of reading an xml file. This queue would be fed by severals threads reading xml in parallel, and consumed by a writing thread, in order to take advantage of all the cores of your cpu.
EDIT:
as a quick-win, i think this code :
JAXBContext context = JAXBContext.newInstance(NotesDocumentMetaFile.class);
Unmarshaller um = context.createUnmarshaller();
can be moved outside the for loop. It should give you a good boost. The context is thread safe, while the unmarshaller is not but can be reused for several files.
I'm having some issue while converting String object to JAXBElement string object where I need to set this one
This is the target method where I need to set the value
public void setData(JAXBElement<String> value) {
this.data = ((JAXBElement<String> ) value);
}
For this one, I have written code something like this
ObjectFactory factory = new ObjectFactory();
JAXBElement<ApplicationIngestionRequest> jaxbElement = new JAXBElement(
new QName(ApplicationIngestionRequest.class.getSimpleName()), ApplicationIngestionRequest.class, request);
StringWriter writer = new StringWriter();
JAXBContext context = JAXBContext.newInstance(ApplicationIngestionRequest.class);
context.createMarshaller().marshal(jaxbElement, writer);
LOG.info("JAXBElement object :\n"+ writer.toString());
Unmarshaller u = context.createUnmarshaller();
JAXBElement<ApplicationIngestionRequest> o = (JAXBElement<ApplicationIngestionRequest>) u.unmarshal(new StringReader(writer));
Log gives me following output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><ApplicationIngestionRequest><BranchCode></BranchCode><SourceCode>0000005511</SourceCode></ApplicationIngestionRequest>
Now when I try to set into the method as
losRequest.setData(o.toString());
It doesn't allow me to set as its expecting as JAXBElement format. Any ideas would be greatly appreciated.
As per the code snippet [setData(JAXBElement value)] , setData , accept instance of '(JAXBElement'). But here , you are trying to set a string value [losRequest.setData(o.toString())] . Here you have to set an instance of 'JAXBElement' .This could be the issue.
i want to know if is possible to me to parse some atributes from a xml file, to be a object in java
I don´t wanna to create all fields that are in xml.
So, how can i do this?
For exemple below there is a xml file, and i want only the data inside the tag .
<emit>
<CNPJ>1109</CNPJ>
<xNome>OESTE</xNome>
<xFant>ABATEDOURO</xFant>
<enderEmit>
<xLgr>RODOVIA</xLgr>
<nro>S/N</nro>
<xCpl>402</xCpl>
<xBairro>GOMES</xBairro>
<cMun>314</cMun>
<xMun>MINAS</xMun>
<UF>MG</UF>
<CEP>35661470</CEP>
<cPais>58</cPais>
<xPais>Brasil</xPais>
<fone>03</fone>
</enderEmit>
<IE>20659</IE>
<CRT>3</CRT>
For Java XML parsing where you don't have the XSD and don't want to create a complete object graph to represent the XML, JDOM is a great tool. It allows you to easily walk the XML tree and pick the elements you are interested in.
Here's some sample code that uses JDOM to pick arbitrary values from the XML doc:
// reading can be done using any of the two 'DOM' or 'SAX' parser
// we have used saxBuilder object here
// please note that this saxBuilder is not internal sax from jdk
SAXBuilder saxBuilder = new SAXBuilder();
// obtain file object
File file = new File("/tmp/emit.xml");
try {
// converted file to document object
Document document = saxBuilder.build(file);
//You don't need this or the ns parameters in getChild()
//if your XML document has no namespace
Namespace ns = Namespace.getNamespace("http://www.example.com/namespace");
// get root node from xml. emit in your sample doc?
Element rootNode = document.getRootElement();
//getChild() assumes one and only one, enderEmit element. Use a lib and error
//checking as needed for your document
Element enderEmitElement = rootNode.getChild("enderEmit", ns);
//now we get two of the child from
Element xCplElement = enderEmitElement.getChild("xCpl", ns);
//should be 402 in your example
String xCplValue = xCplElement.getText();
System.out.println("xCpl: " + xCplValue);
Element cMunElement = enderEmitElement.getChild("cMun", ns);
//should be 314 in your example
String cMunValue = cMunElement.getText();
System.out.println("cMun: " + cMunValue);
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
You can use JAXB to unmarshal the xml into Java object, with which you can read selective elements easily. With JAXB, the given XML can be represented in Java as follows :
enderEmit element :
#XmlRootElement
public class EnderEmit{
private String xLgr;
//Other elements.Here you can define properties for only those elements that you want to load
}
emit element (This represents your XML file):
#XmlRootElement
public class Emit{
private String cnpj;
private String xnom;
private EnderEmit enderEmit;
..
//Add elements that you want to load
}
Now by using the below lines of code, you can read your xml to an object :
String filePath="filePath";
File file = new File(filePath);
JAXBContext jaxbContext = JAXBContext.newInstance(Emit.class);
jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Emit emit = (Emit) jaxbUnmarshaller.unmarshal(file);
The line will give you an emit object for the given xml.
Try to use StringUtils.subStringBetween
try
{
String input = "";
br = new BufferedReader(new FileReader(FILEPATH));
String result = null;
while ((input = br.readLine()) != null) // here we read the file line by line
{
result = StringUtils.substringBetween(input, ">", "<"); // using StringUtils.subStringBetween to get the data what you want
if(result != null) // if the result should not be null because some of the line not having the tags
{
System.out.println(""+result);
}
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if (br != null)
{
br.close();
}
}
catch (IOException ex)
{
ex.printStackTrace();
}
}