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.
Related
I'm trying to create an XML and return it as a response to the caller based on the input.
The transformer works as expected for most parts, but it doesn't convert apostrophe and quotes to their XML equivalent. Below is the code I'm using
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
// root elements
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("template");
doc.appendChild(rootElement);
/* Adding attendant ID */
Element line = doc.createElement("line");
line.appendChild(doc.createTextNode("----&----<------>------'-----\"--------"));
Attr Attr1 = doc.createAttribute("Attr1");
Attr1.setValue("attribute value 1");
line.setAttributeNode(Attr1);
Attr Attr2 = doc.createAttribute("Attr2");
Attr2.setValue("attribute value 2");
line.setAttributeNode(Attr2);
rootElement.appendChild(line);
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
// Output to String
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
String strResult = writer.toString();
//return escapeXml(strResult);
System.out.println(strResult);
Resulting output
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<template>
<line Attr1="attribute value 1" Attr2="attribute value 2">----&----<------>------'-----"--------</line>
</template>
Expected Result
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<template>
<line Attr1="attribute value 1" Attr2="attribute value 2">----&----<------>------'-----"--------</line>
</template>
Initially I thought could escape those character before sending it as input to transformer, but it replaced all the ampersand to their equivalent "&". If I replace the apostrophe or quotes after the final XML is created, it replaces attributes as well.
I'm thinking we could solve this in 2 ways
I could transform the & , < , > , ' , " before adding to node and transformer ignores it
Give explicit directions to transformer to convert ' , " them to their XML equivalent.
Currently I'm unaware of how to achieve these. Could someone help me on this or if a better solution to create a valid XML would hugely be appreciated.
Thanks.
Why do you want quotation marks and apostrophes to be escaped? XML doesn't require them to be escaped (except in attributes where they conflict with the attribute delimiters). The serializer knows what it's doing: trust it.
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.
I searched on google first and I found many result about how to parse with xpath a xml document. I have parse it but a want to convert a NODELIST in String and I have created a method for it:
private String processResult(Document responseDocument) throws XPathExpressionException, TransformerException {
NodeList soaphead = responseDocument.getElementsByTagName("xmlTagToTrasform");
StringWriter sw = new StringWriter();
Transformer serializer = TransformerFactory.newInstance().newTransformer();
serializer.transform(new DOMSource(soaphead.item(0)), new StreamResult(sw));
String result = sw.toString();
return result;
}
This method works perfectly but the transformer adds an <?xml version="1.0" encoding="UTF-8"?> in the header of the result, and I don't want that. This is the result of the method:
<?xml version="1.0" encoding="UTF-8"?>
<xmlTagToTrasform>
<xmlTagToTrasform2>
.
.
.
.
</xmlTagToTrasform2>
</xmlTagToTrasform>
You can configure the transformer not to output the XML declaration, before you call transform:
serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
XML is a markup language and every xml document has this line on the top to specify the version and the encoding-type. It is madatory to have this.
How to append a child element to a root element by using DOM. Here is my XML file.
<?xml version="1.0" encoding="utf-8"?>
<array>
<recipe>
<name>Name First</name>
<description>Description First</description>
<instruction>Instruction First</instruction>
</recipe>
<recipe>
<name>Name Second</name>
<description>Description Second</description>
<instruction>Instruction Second</instruction>
</recipe>
</array>
I want to add a new <recipe> tag as a child of <array> tag. Here is my java code that I have developed in this respect, this code shows me log message properly and there is no error but it does not add new child, please help me and I identify that where I am going wrong. Thanks in advance.
private void addRecipeToMyRecipeFile(MyRecipeModel recipeModel)
{
MyRecipeModel mRecipe = recipeModel;
MyRecipeHandler recipeHandler = new MyRecipeHandler();
// Here I get the content of XML file as a string and convert the string in XML format
Document doc = convertRecipesFileIntoXML(recipeHandler.getContentOfMyRecipesFileFromSDCard());
Log.e("Doc", "convertRecipesFileIntoXML");
final NodeList nodes_array = doc.getElementsByTagName(TAG_ARRAY);
//We have encountered an <array> tag.
Element rootArrayTag = (Element)nodes_array.item(0);
Log.e("Element", "Array");
// <recipe> elements
Element recipe = doc.createElement(TAG_RECIPE);
rootArrayTag.appendChild(recipe);
Log.e("Element", "Recipe");
// <name> is name of recipe
Element name = doc.createElement(TAG_RECIPE_NAME);
name.appendChild(doc.createTextNode(mRecipe.getMyRecipeName()));
recipe.appendChild(name);
Log.e("Element", "Name");
// <description> is description of the recipe
Element description = doc.createElement(TAG_RECIPE_DESCRIPTION);
description.appendChild(doc.createTextNode(mRecipe.getMyRecipeDescription()));
recipe.appendChild(description);
Log.e("Element", "Description");
// <instructions> elements
Element instructions = doc.createElement(TAG_RECIPE_INSTRUCTION);
instructions.appendChild(doc.createCDATASection(mRecipe.getMyRecipeInstruction()));
recipe.appendChild(instructions);
Log.e("Element", "Instruction");
}
I don't think there is problem in your code to manipulate DOM objects. But what is missing is that you need to output you DOM object somewhere, e.g. a file. Otherwise, the objects are just some memory blocks, and they don't automatically persist to your source file.
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(filepath));
transformer.transform(source, result);
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">