i am trying to add elements to xml document. Elements are added successfuly but problem is, that parser modifies original xml file in other places e.g it swaps namespace and id attributes or deletes duplicate namespace definitions. I need to get precisely the same document (same syntax, preserved whitespaces) only with specific elements added. I would greatly appreciate any suggestions. Here is my code:
public void appendTimestamp(String timestamp, String signedXMLFile, String timestampedXMLFile){
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try{
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File(signedXMLFile));
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList list = (NodeList)xPath.evaluate("//*[local-name()='Signature']/*[local-name()='Object']/*[local-name()='QualifyingProperties']", doc, XPathConstants.NODESET);
if(list.getLength() != 1){
throw new Exception();
}
Node node = list.item(0);
Node unsignedProps = doc.createElement("xades:UnsignedProperties");
Node unsignedSignatureProps = doc.createElement("xzep:UnsignedSignatureProperties");
Node timestampNode = doc.createElement("xzep:SignatureTimeStamp");
timestampNode.appendChild(doc.createTextNode(timestamp));
unsignedSignatureProps.appendChild(timestampNode);
unsignedProps.appendChild(unsignedSignatureProps);
node.appendChild(unsignedProps);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
DOMSource source = new DOMSource(doc);
StringWriter writer = new StringWriter();
StreamResult stringWriter = new StreamResult(writer);
transformer.transform(source, stringWriter);
writer.flush();
System.out.println(writer.toString());
}catch(Exception e){
e.printStackTrace();
}
}
The original xml file:
...
<ds:Object Id="objectIdVerificationObject" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
...
Modified xml file:
...
<ds:Object xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="objectIdVerificationObject">
...
If you use the dom model, then the whole xml file is read, then represented in the memory as the node tree and then saved to xml in a way determined by the writer. So it is almost impossible to preserve the original xml format as you don't have the control over it and for example whitespaces are not represented at all in the node tree.
You need to read partially the original xml and ouptut its content to the new file preserving what was read, then in the "right" place you need to add your new content adn then continue simple coapying of the original.
For example you could use the XMLStreamWriter and XMLStreamReader to achieve that as they offer "the low" level operations.
But probably it would be much easier to just copy the xml as the text line by one till you recognize the insertion point, then create new xml portion and append it as text and continue with copying.
Related
I have XML about article
<ARTICLE ID="74">
<ARTICLE_CATEGORY_ID>1</ARTICLE_CATEGORY_ID >
<ARTICLE_NAME>......</ARTICLE_NAME >
<ARTICLE_EXTENSION>pdf</ARTICLE_EXTENSION >
<ARTICLE_BYTE>[B#6d78f375</ARTICLE_BYTE >
<ARTICLE_DATE>2014-10-11 00:00:00.0</ARTICLE_DATE >
<ARTICLE_ACTIVE>1</ARTICLE_ACTIVE>
</MAKALE>
i want to create file ,and write ARTICLE_BYTE but i can't do it ,it seems, byte seems is String i quess so i don't know how can i do this ? Thank you for helping
//EDIT
Sorry i'm very new stackoverflow..
yes this is from a program that i've written.
That's part of code from the program
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
// XML Kok Ismi
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("ARTICLES");
doc.appendChild(rootElement);
for (Nesne nesne : userList) {
// ARTICLE ELEMENT
Element ARTICLE_ID= doc.createElement("ARTICLE ");
rootElement.appendChild(ARTICLE_ID);
//ID
Attr attr = doc.createAttribute("ID");
attr.setValue(String.valueOf(nesne.getArticleID()));
MAKALE_ID.setAttributeNode(attr);
//ARTICLE_CATEGORY_ID
Element ARTICLE_CATEGORY_ID= doc.createElement("ARTICLE_CATEGORY_ID");
ARTICLE_CATEGORY_ID.appendChild(doc.createTextNode(String.valueOf(nesne.getARTICLE_CATEGORY_ID())));
ARTICLE_ID.appendChild(ARTICLE_CATEGORY_ID);
//[ARTICLE_NAME]
Element ARTICLE_NAME= doc.createElement("ARTICLE_NAME");
ARTICLE_NAME.appendChild(doc.createTextNode(nesne.getARTICLE_NAME()));
ARTICLE_ID.appendChild(ARTICLE_NAME);
//[ARTICLE_EXTENSION]
Element ARTICLE_EXTENSION= doc.createElement("ARTICLE_EXTENSION");
ARTICLE_EXTENSION.appendChild(doc.createTextNode(nesne.getARTICLE_EXTENSION()));
ARTICLE_ID.appendChild(ARTICLE_EXTENSION);
//[ARTICLE_BYTE]
Element ARTICLE_BYTE= doc.createElement("ARTICLE_BYTE");
ARTICLE_BYTE.appendChild(doc.createTextNode(nesne.getARTICLE_BYTE().toString()));
ARTICLE_ID.appendChild(ARTICLE_BYTE);
//[ARTICLE_DATE]
Element ARTICLE_DATE = doc.createElement("ARTICLE_DATE");
ARTICLE_DATE.appendChild(doc.createTextNode(nesne.getARTICLE_DATE()));
ARTICLE_ID.appendChild(ARTICLE_DATE);
//[ARTICLE_ACTIVE]
Element ARTICLE_ACTIVE= doc.createElement("ARTICLE_ACTIVE");
ARTICLE_ACTIVE.appendChild(doc.createTextNode(String.valueOf(nesne.getArticleActive())));
ARTICLE_ID.appendChild(ARTICLE_ACTIVE);
}
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File("dosyalar.xml"));
// Output to console for testing
// StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
System.out.println("File saved!");
Your problem appears to be here:
nesne.getARTICLE_BYTE().toString()
I'm not familiar with your Nesne class, but I can tell that the method, getARTICLE_BYTE() returns a byte array, that calling toString() on it will return the useless information that you're currently seeing, and that if this needs to be stored, then you somehow need to store the entire array. Using a for loop and storing the array as the String representations of each byte would not be the most efficient thing to do and would lead to a super-large unreadable XML, so perhaps you could store it off of the XML and pass a reference to the byte array file in the XML. Or store in a database as a BLOB. Note that this is not something I do much of, and so I'm no expert.
I'm updating node and text content of the xml using DOM parser. To save that DOM parser I'm using transformer.transform method.
Below is the sample code.
String xmlText = "<uc>abcd><name>mine</name>efgh\netg<tag>sd</tag></uc>";
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
InputSource inStream = new InputSource();
inStream.setCharacterStream(new StringReader(xmlText));
Document document = documentBuilder.parse(inStream);
Node node = document.getDocumentElement();
node.normalize();
NodeList childNodes = node.getChildNodes();
for(int i=0; i<childNodes.getLength(); i++) {
if(childNodes.item(i).getNodeType() == Node.TEXT_NODE) {
System.out.println(childNodes.item(i).getTextContent());
childNodes.item(i).setTextContent("123>");
}
}
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.ENCODING, "US-ASCII");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
DOMSource source = new DOMSource( document );
OutputStream xml = new ByteArrayOutputStream();
StreamResult result = new StreamResult( xml );
transformer.transform( source, result );
String formattedXml = xml.toString();
System.out.println(formattedXml);
Since my updated document is having text content like ">", transformer.transform method is changing it to &g t;
Is there a way to get the output without escaping special characters.
I can't use other parser because of some project constraints.
I can't use StringEscapeUtils.unescapeXml(). The reason is xml can have &g t;. If i use this utility method, &g t; which was originally present in the xml will also get changed.
So i want a mechanism which will not escape any special character.
The transformer you create with
Transformer transformer = tFactory.newTransformer();
is initialized with a default stylesheed that implements the identity transformation. That means it will simply serialize your DOM to a well-formed XML document. Output escaping is automatically applied where necessary.
If you want better control over the output, and possibly generate something that does not adhere to XML document structures, you can use a custom stylesheet that switches the output method to text. This way you control more of the structure but can do more mistakes in the XML area.
More information at
https://docs.oracle.com/en/java/javase/11/docs/api/java.xml/javax/xml/transform/TransformerFactory.html#newTransformer()
https://www.w3.org/TR/xslt20/#element-output
I am trying to build an XML document using a specific namespace. The final document I am trying to generate is supposed to look like this:
<m:documentObject xmlns:m="http://www.myschema.com">
<sender>token</sender>
<receiver>token</receiver>
<payload>token</payload>
</m:documentObject>
Here is what i have so far.
Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element requestElement = document.createElementNS("http://www.myschema.com", "documentObject");
document.appendChild(requestElement);
Element sender = document.createElement("sender");
requestElement.appendChild(sender);
Text senderText = document.createTextNode("Xmlsender");
sender.appendChild(senderText);
Element receiver = document.createElement("receiver");
requestElement.appendChild(receiver);
Text receiverText = document.createTextNode("Xmlreceiver");
receiver.appendChild(receiverText);
Element payload = document.createElement("payload");
requestElement.appendChild(payload);
Text payloadText = document.createTextNode("Xmlpayload");
payload.appendChild(payloadText);
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
DOMSource source = new DOMSource(requestElement);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "utf-8");
transformer.transform(source, result);
String xmlString = sw.toString();
System.out.println(xmlString)
For some reason when I run the above the schema comes out without the prefix. As shown below:
<?xml version="1.0" encoding="utf-8"?>
<documentObject xmlns="http://www.myschema.com">
<sender>Xmlsender</sender>
<receiver>Xmlreceiver</receiver>
<payload>Xmlpayload</payload>
</documentObject>
What do I need to do so that XML is exactly as shown in the first XML example with the namespace prefix and the tags to have the namespace prefix?
I am trying to create an XML string which will be used for a Spring-WS webservice which expects a JAXB object which is in the format shown in the first example.
You can use setPrefix.
But it is better to create the root element like this:
document.createElementNS("http://www.myschema.com", "m:documentObject");
Note also that passing null to createElement is a supported way of forcing a null namespace. In your original example this would however not work because your document element effectively forces a default namespace by combining a namespace URI with no prefix.
I am currently creating an XML document in Java. The document should have the following structure:
<?xml version="1.0" ?>
<Cancelacion xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
RfcEmisor="VSI850514HX4"
Fecha="2011-11-23T17:25:06"
xmlns="http://cancelacfd.sat.gob.mx">
<Folios>
<UUID>BD6CA3B1-E565-4985-88A9-694A6DD48448</UUID>
</Folios>
</Cancelacion>
I want to know if there is a special way to create the attributes with form xmlns:xsd?
I am currently declaring this attribute like this:
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder;
docBuilder = dbfac.newDocumentBuilder();
Document doc = docBuilder.newDocument();
doc.setXmlVersion("1.0");
doc.setXmlStandalone(true);
Element cancelacion = doc.createElement("Cancelacion");
cancelacion.setAttribute("xmlns", "http://cancelacfd.sat.gob.mx");
cancelacion.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
cancelacion.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
cancelacion.setAttribute("RfcEmisor", rfc);
cancelacion.setAttribute("Fecha", fecha);
The solution my problem is to write the code as follows:
//Crear un document XML vacĂo
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
dbfac.setNamespaceAware(true);
DocumentBuilder docBuilder;
docBuilder = dbfac.newDocumentBuilder();
DOMImplementation domImpl = docBuilder.getDOMImplementation();
Document doc = domImpl.createDocument("http://cancelacfd.sat.gob.mx", "Cancelacion", null);
doc.setXmlVersion("1.0");
doc.setXmlStandalone(true);
Element cancelacion = doc.getDocumentElement();
cancelacion.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xsd","http://www.w3.org/2001/XMLSchema");
cancelacion.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance");
cancelacion.setAttribute("RfcEmisor", rfc);
cancelacion.setAttribute("Fecha", fecha);
Element folios = doc.createElement("Folios");
cancelacion.appendChild(folios);
for (int i=0; i<uuid.length; i++) {
Element u = doc.createElement("UUID");
u.setTextContent(uuid[i]);
folios.appendChild(u);
}
Why should the document have your proposed structure? You're declaring namespaces with prefixes, but your example output doesn't include any elements in those namespaces. Those declarations are therefore unnecessary.
First, understand that xmlns (or xmlns:prefix) is the reserved XML pseudo-attribute for declaring namespaces. It's not a normal attribute. Second, the location of namespace declarations in the document shouldn't concern you, as long as you're creating elements in the desired namespaces in the first place.
Let the serializer decide where to place the namespace declarations.
Register an element in the correct namespace like this:
Element cancelacion = doc.createElementNS(
"http://cancelacfd.sat.gob.mx", "Cancelacion");
doc.appendChild(cancelacion);
Element child = doc.createElementNS("http://cancelacfd.sat.gob.mx",
"SomeChild");
cancelacion.appendChild(child);
When serialized:
DOMSource domSource = new DOMSource(doc);
StreamResult streamResult = new StreamResult(System.out);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
serializer.transform(domSource, streamResult);
Result:
<Cancelacion xmlns="http://cancelacfd.sat.gob.mx">
<SomeChild/>
</Cancelacion>
Notice that Cancelacion and SomeChild were created in exactly the same way, but only Cancelacion contains the namespace declaration (because the declaration applies for all descendants). The serializer handled this for us.
Warning: What follows is a hack. I do not recommend using it. It will probably get you into trouble. You should probably stop reading. But...if you have no choice, it might work.
If you're desperate, you could manually splice in the unused namespaces. (Treating XML as a string is almost always a bad idea.)
First, save the result in an OutputStream that can be converted to a String:
ByteArrayOutputStream out = new ByteArrayOutputStream();
DOMSource domSource = new DOMSource(doc);
StreamResult streamResult = new StreamResult(out);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
serializer.transform(domSource, streamResult);
Then jam the namespace declarations in there without any regard for what is good, right, and decent:
String[] parts = out.toString().split("\\\">", 2);
String result = parts[0] +
" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" +
" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" + parts[1];
xmlns:xsd is not an attribute, its a namespace declaration.
The DOM should create these declarations as and when they are needed.
Using the createElementNS and createAttributeNS methods will result in namespace declarations being created, but you need to understand XML namespaces.
In your example, the namespaces bound to xsd and xsi are not used so are superfluous. However, the Cancelacion element is in the default namespace which is defined by the xmlns="http://cancelacfd.sat.gob.mx" declaration in the XML you have provided.
So you should use:
doc.createElementNS("http://cancelacfd.sat.gob.mx", "Cancelacion");
to create that. Note that the namespace prefix (or lack thereof) is irrelevant as far as the meaning of the document is concerned.
in my code, I wrote :
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.newDocument();
Element spectraexchage = document.createElementNS("http://www.lstelcom.com/Schema/SPECTRAexchange", "SPECTRAEXCHANGE");
spectraexchage.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
spectraexchage.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
spectraexchage.setAttribute("version", "2.4.28");
document.appendChild(spectraexchage);
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
output :
<SPECTRAEXCHANGE xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.4.28" xmlns="http://www.lstelcom.com/Schema/SPECTRAexchange">
I've seen many many articles on how to read XML into a JTree but few on how to create the XML from the JTree. Can anyone help me with a simple approach for this? I've seen an example that looked like:
XMLEncoder e = new XMLEncoder(
new BufferedOutputStream(new FileOutputStream(f.toString())));
e.writeObject(o);
e.close();
.. but I can't get this to work; it returns an XML file but its not quite right, looking like this:
<java version="1.6.0_17" class="java.beans.XMLDecoder">
<object class="javax.swing.JTree">
<object class="javax.swing.tree.DefaultTreeModel">
<object class="javax.swing.tree.DefaultMutableTreeNode">
<void property="userObject">
.. etc, but with none of my data in there.
(PS: Please be gentle, I'm very new to java!)
The XMLEncoder is a generic utility for encoding beans as text. I don't think it is suitable in your case.
I wrote a piece of code that does the job, assuming that I understand well your needs. You only have to pass the tree model as a parameter to the toXml method. Note that this is just a draft; You will probably want to handle exceptions differently, and manage your transformation parameters differently. More important, you can manipulate the recursive createTree method in order to change the structure of the XML node created per tree node.
public static String toXml(TreeModel model) throws ParserConfigurationException, TransformerException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
DOMImplementation impl = builder.getDOMImplementation();
// Build an XML document from the tree model
Document doc = impl.createDocument(null,null,null);
Element root = createTree(doc, model, model.getRoot());
doc.appendChild(root);
// Transform the document into a string
DOMSource domSource = new DOMSource(doc);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING,"UTF-8");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter sw = new StringWriter();
StreamResult sr = new StreamResult(sw);
transformer.transform(domSource, sr);
return sw.toString();
}
private static Element createTree(Document doc, TreeModel model, Object node) {
Element el = doc.createElement(node.toString());
for(int i=0;i<model.getChildCount(node);i++){
Object child = model.getChild(node, i);
el.appendChild(createTree(doc,model,child));
}
return el;
}