I need to generate an xml file in Java, so I chose to use DOM (until there everything is ok), here is the root tag of what i need to create
<?xml version="1.0" encoding="utf-8"?>
<KeyContainer Version="1.0" xmlns="urn:ietf:params:xml:ns:keyprov:pskc:1.0" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:xml="http://www.w3.org/XML/1998/namespace">
Here is my source code
PrintWriter out = new PrintWriter(path);
Document xmldoc = null;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
DOMImplementation impl = builder.getDOMImplementation();
Element e = null;
Node n = null;
xmldoc = impl.createDocument(null, "KeyContainer", null);
/* Noeuds non bouclés */
Element keycontainer = xmldoc.getDocumentElement();
keycontainer.setAttributeNS(null, "Version", "1.0");
keycontainer.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:ds","http://www.w3.org/2000/09/xmldsig#");
keycontainer.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xenc", "http://www.w3.org/2001/04/xmlenc#");
keycontainer.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xml", "http://www.w3.org/XML/1998/namespace");
keycontainer.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "urn:ietf:params:xml:ns:keyprov:pskc:1.0");
/* Non relevant Info*/
DOMSource domSource = new DOMSource(xmldoc);
StreamResult streamResult = new StreamResult(out);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer serializer = tf.newTransformer();
serializer.setOutputProperty(OutputKeys.ENCODING,"utf-8");
serializer.setOutputProperty(OutputKeys.VERSION,"1.0");
serializer.setOutputProperty(OutputKeys.INDENT,"yes");
serializer.setOutputProperty(OutputKeys.STANDALONE,"yes");
serializer.transform(domSource, streamResult);
And here is what I get
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<KeyContainer xmlns="" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Version="1.0">
Problem is the xmlns property is empty, and xmlns:xml is missing, what can I do to get all information ?
Thanks a lot stackoverflow
(PS : Got NAMESPACE_ERR if anything else than "http://www.w3.org/2000/xmlns/" in NamespaceURI field)
Two things are required to get rid of xmlns=""
Create the Document with the desired namespace URI as such:
xmldoc = impl.createDocument("urn:ietf:params:xml:ns:keyprov:pskc:1.0", "KeyContainer", null);
Remove the following line as it is now unnecessary:
keycontainer.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns", "urn:ietf:params:xml:ns:keyprov:pskc:1.0");
Regarding the xmlns:xml attribute, the API is silently dropping it. See line 173 of NamespaceMappings. A bit of research turns up that the behavior of declaring that particular namespace is undefined and is not recommended.
To make DOM namespace aware, do not forget to enable it in the documentbuilderfactory using the setNamespaceAware method.
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.
My XML looks like below and I need to extract multiple ID element in
an output xml:-
<?xml version="1.0" encoding="utf-8"?>
<Stock>
<PIdentification>
<CatalogVersion></CatalogVersion>
<AccountID></AccountID>
<CustomerId></CustomerId>
</ProviderIdentification>
<Product>
<ArticleName>Monitors</ArticleName>
<BaseUnit></BaseUnit>
<Notes></Notes>
<ID>11f13e2e-ae97-45b5-a9a9-23fa7f6bb767</ID>
<ID>b22834c0-a570-4e6b-97c3-5067a14d118d</ID>
<ID>ed458593-5e1a-4dc1-94f0-a66eeef2dd79</ID>
<ID>d25584a9-1db2-48cf-9a70-9b81e5a7e7f2</ID>
</Product>
</Stock>
I have used "Nodelist" to extract "ID" but I am getting just one element
and not all 4, below is the part of the code:-
{
Node IDNode = element.getElementsByTagName("ID").item(0);
IDXml = toStringXml(IDNode , true);
}
I am not able to reiterate for look to get all the IDs, please let me
know how to get all ID, any help is appreciated.
private static String toStringXml(Node elt, boolean xmlDeclaration)
throws TransformerException {
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
if(xmlDeclaration)
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
DOMSource source = new DOMSource(elt);
StreamResult result = new StreamResult(new StringWriter());
transformer.transform(source, result);
return result.getWriter().toString();
}
You got all id's but you are only looking at first item with .item(id).
Method getElementsByTageName("ID") returns you NodeList so you can got trough all ids for example like that:
File xmlFile = new File("src/main/resources/example.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document element = dBuilder.parse(xmlFile);
NodeList list = element.getElementsByTagName("ID");
for (int i = 0; i < list.getLength(); i++){
Node specificIDNode = list.item(i);
System.out.println(specificIDNode.getTextContent());
}
You have malformed XML displayed in your question. Unclosed <PIdentification> tag on the row 3.
Correct XML code should look like that:
<?xml version="1.0" encoding="utf-8"?>
<Stock>
<ProviderIdentification>
<CatalogVersion></CatalogVersion>
<AccountID></AccountID>
<CustomerId></CustomerId>
</ProviderIdentification>
<Product>
<ArticleName>Monitors</ArticleName>
<BaseUnit></BaseUnit>
<Notes></Notes>
<ID>11f13e2e-ae97-45b5-a9a9-23fa7f6bb767</ID>
<ID>b22834c0-a570-4e6b-97c3-5067a14d118d</ID>
<ID>ed458593-5e1a-4dc1-94f0-a66eeef2dd79</ID>
<ID>d25584a9-1db2-48cf-9a70-9b81e5a7e7f2</ID>
</Product>
</Stock>
And in this case, code, provided by #Penguin74 displays all IDS from your xml (check the picture below).
I recently just started working with document builder to build a title with my XML. This is the following code I am using right now:
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
InputStream inputStream = new FileInputStream(new File("c:\\staff.xml"));
org.w3c.dom.Document doc = documentBuilderFactory.newDocumentBuilder().parse(inputStream);
StringWriter stw = new StringWriter();
Transformer serializer = TransformerFactory.newInstance().newTransformer();
serializer.transform(new DOMSource(doc), new StreamResult(stw));
String xmldata = (stw.toString());
System.out.println(xmldata);
It builds the title fine, but it starts writing the XML file on the same line due to the parse. Can someone show me how I can alter this code to get <company> onto the second line?
Here is my print:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><company>
<comp id="512">
<firstname>Brandon</firstname>
<lastname>Liens</lastname>
<empid>612</empid>
<rqid>51265</rqid>
</comp>
</company>
Staff.XML file:
<company>
<comp id="512">
<firstname>Brandon</firstname>
<lastname>Nyberg</lastname>
<empid>612</empid>
<rqid>51265</rqid>
</comp>
</company>
You can't add a newline after the XML declaration automatically, but if you can deal with removing the XML declaration entirely, you can add this line just after your Transformer serializer = ... line:
serializer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
I am trying to dynamically generate XML schema using Xerces-J and getting the following error, appreciate any help regarding it.
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
dbfac.setNamespaceAware(true);
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element schema = doc.createElement("xs:schema");
schema.setAttribute("xmlns:xs", "http://www.w3.org/2001/XMLSchema");
doc.appendChild(schema);
Element e = doc.createElement("xs:element");
e.setAttribute("name", "test");
e.setAttribute("type", "xs:string");
schema.appendChild(e);
TransformerFactory transfac = TransformerFactory.newInstance();
Transformer trans = transfac.newTransformer();
trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
trans.setOutputProperty(OutputKeys.INDENT, "yes");
//create string from xml tree
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(sw);
DOMSource source = new DOMSource(doc);
trans.transform(source, result);
String xmlString = sw.toString();
System.out.println(xmlString);
SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
Schema schema1 = schemaFactory.newSchema(source);
Output is
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="test" type="xs:string"/>
</xs:schema>
org.xml.sax.SAXParseException: s4s-elt-schema-ns: The namespace of element 'xs:schema' must be from
the schema namespace, 'http://www.w3.org/2001/XMLSchema'.
When building a DOM, you don't specify namespaces as attributes. Instead, use the version of createElement() that takes two parameters: the first is the namespace URI, the second is the element's qualified name.
Note also that the prefix of a qualified name will automatically be matched to the namespace URI. If you want, you could eliminate the prefix altogether, and the serializer will do the right thing (either creating an xmlns attribute without prefix, or generating a prefix).
I had the similar problem and found the Apache Commons XMLSchema
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">