How to update the XML node from <ns0:Request> to <ns1:Request xmlns:ns1="with some URL">
in Java using DOM parser.
I do not want to use the replaceAll() method.
You can do the following using the Node.replaceChild(Node, Node) method:
http://docs.oracle.com/javase/7/docs/api/org/w3c/dom/Node.html#replaceChild%28org.w3c.dom.Node,%20org.w3c.dom.Node%29
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class Demo {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
// Create original document
Document document = db.newDocument();
Element root = document.createElementNS("urn:FOO", "ns0:Root");
document.appendChild(root);
Element request = document.createElementNS("urn:FOO", "ns0:Request");
root.appendChild(request);
// Create new Request element.
Element newRequest = document.createElementNS("urn:BAR", "ns1:Request");
// Replace Request element
root.replaceChild(newRequest, request);
// Output the new document
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(System.out);
t.transform(source, result);
}
}
Related
I have the below code that appends to an xml file. The problem is that it includes the xml configuration line each time it appends along with the main element. It works fine for the first record added to the file because there is not previous existing elements. How would I modify this code to exclude those lines for an existing file with existing elements?
import java.io.FileWriter;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
public class WriteXMLFile {
public static void main() throws ParserConfigurationException,SAXException,Exception{
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();//
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();//
Document doc = docBuilder.newDocument();// this is difrent
Element rootElement = doc.createElement("Contacts");//
doc.appendChild(rootElement); // this is difrent
Element Contact1 = doc.createElement("Contact1");
rootElement.appendChild(Contact1);
Contact1.setAttribute("id","1");
Element firstname = doc.createElement("Name");
firstname.appendChild(doc.createTextNode(EmailFrame.name.getText()));
Contact1.appendChild(firstname);
//Email Element
Element email = doc.createElement("Email");
email.appendChild(doc.createTextNode(EmailFrame.email.getText()));
Contact1.appendChild(email);
// phone element
Element phone= doc.createElement("Phone");
phone.appendChild(doc.createTextNode(EmailFrame.phone.getText()));
Contact1.appendChild(phone);
//id element
Element id = doc.createElement("ID");
id.appendChild(doc.createTextNode(EmailFrame.id.getText()));
Contact1.appendChild(id);
try{
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new FileWriter("C:/Users/steve/Desktop/xmlemail/Email.xml",true));
transformer.transform(source, result);
System.out.println("File saved!");
}
catch (TransformerException tfe) {
tfe.printStackTrace();
}
}}
If you are looking for "overriding" the file then you shall use
StreamResult result = new StreamResult(new FileWriter("D:/tmp/Email.xml")); as boolean parameter just appends to the document.
If you indeed want to append but don't want <?xml version="1.0" encoding="UTF-8" standalone="no"?> then you will have to "read" the file, get the root node and then add elements to the root node.
Remember if you just keep on adding nodes to the document and not to the root element, then even without <?xml version="1.0" encoding="UTF-8" standalone="no"?>, your xml will be invalid, as it will contain multiple root elements "contacts".
Something like:
Document doc = null;
Node rootElement = null;
if (f.exists()) {
doc = docBuilder.parse("C:/Users/steve/Desktop/xmlemail/Email.xml");
rootElement = doc.getFirstChild();//
} else {
doc = docBuilder.newDocument();// this is difrent
rootElement = doc.createElement("Contacts");//
doc.appendChild(rootElement); // this is difrent
}
And then save the document to file without appending.
I am trying to transform the following XML
<PHONEBOOK>
<PERSON>
<NAME>Ren1</NAME>
<EMAIL>ren1#gmail.com</EMAIL>
<TELEPHONE>999-999-9999</TELEPHONE>
<WEB>www.ren1.com</WEB>
</PERSON>
<PERSON>
<NAME>Ren2</NAME>
<EMAIL>ren2#gmail.com</EMAIL>
<TELEPHONE>999-999-9999</TELEPHONE>
<WEB>www.ren2.com</WEB>
</PERSON>
<PERSON>
<NAME>Ren3</NAME>
<EMAIL>ren3#gmail.com</EMAIL>
<TELEPHONE>999-999-9999</TELEPHONE>
<WEB>www.ren3.com</WEB>
</PERSON>
</PHONEBOOK>
to
<Names><Name>Ren1</Name><Name>Ren2</Name><Name>Ren3</Name></Names>
using DOMSource, DOMResult and XSLT.
XSLT used is as follows
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output omit-xml-declaration="yes" method="xml"></xsl:output>
<xsl:template match="/">
<Names>
<xsl:for-each select="PHONEBOOK/PERSON">
<Name>
<xsl:value-of select="NAME" />
</Name>
</xsl:for-each>
</Names>
Java Code used for transformation:
package test1;
import java.io.IOException;
import java.io.StringWriter;
import java.io.ObjectInputStream.GetField;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
public class Test2 {
public static void main(String[] args) throws TransformerException,
ParserConfigurationException, SAXException, IOException {
// TODO Auto-generated method stub
//Stylesheet
StreamSource stylesource = new StreamSource(
"src/test1/transform_stylesheet1.xsl");
DocumentBuilderFactory docbFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder dBuilder = docbFactory.newDocumentBuilder();
//source XML
Document sourceDoc = dBuilder.parse("src/test1/Sample1.xml");
DOMSource source = new DOMSource(sourceDoc);
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory
.newTransformer(stylesource);
Document document = dBuilder.newDocument();
DOMResult result = new DOMResult(document);
transformer.transform(source, result);
Node resultDoc = ((Document) result.getNode()).getDocumentElement();
System.out.println(resultDoc.getChildNodes().getLength());
// print the result
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(resultDoc), new StreamResult(writer));
String str = writer.toString();
System.out.println(str);
}
}
Output of the above is as follows:
3 <Names/>
but i expect,
3
<Names><Name>Ren1</Name><Name>Ren2</Name><Name>Ren3</Name></Names>
i debugged the code and found that 'resultDoc' has the content which i expect. Am i missing something while printing the result?
Your problem is that you're using the same transformer for the stylesheet processing and the output. That means, the stylesheet is applied again, but this time to the <Names><Name>Ren1</Name>...</Names> xml. You can imagine that this doesn't give the results you want.
Change your code to:
// print the result
StringWriter writer = new StringWriter();
Transformer transformer2 = transformerFactory.newTransformer();
transformer2.transform(new DOMSource(resultDoc), new StreamResult(writer));
String str = writer.toString();
System.out.println(str);
and it should work.
As #Abel mentions, you can also do the stylesheet processing and the to String in one go:
StringWriter writer = new StringWriter();
transformer.transform(source, new StreamResult(writer));
String str = writer.toString();
System.out.println(str);
You don't need the DOMResult and DOMSource variables then.
In my XML file I have some entities such as ’
So I have created a DTD tag for my XML document to define these entities. Below is the Java code used to read the XML file.
SAXBuilder builder = new SAXBuilder();
URL url = new URL("http://127.0.0.1:8080/sample/subject.xml");
InputStream stream = url.openStream();
org.jdom.Document document = builder.build(stream);
Element root = document.getRootElement();
Element name = root.getChild("name");
result = name.getText();
System.err.println(result);
How can I change the Java code to retrieve a DTD over HTTP to allow the parsing of my XML document to be error free?
Simplified example of the xml document.
<main>
<name>hello ‘ world ’ foo & bar </name>
</main>
One way to do this would be to read the document and then validate it with the transformer:
import java.net.URL;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
public class ValidateWithExternalDTD {
private static final String URL = "http://127.0.0.1:8080/sample/subject.xml";
private static final String DTD = "http://127.0.0.1/YourDTD.dtd";
public static void main(String args[]) {
try {
DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance();
factory.setValidating(true);
DocumentBuilder builder = factory.newDocumentBuilder();
// Set the error handler
builder.setErrorHandler(new org.xml.sax.ErrorHandler() {
public void fatalError(SAXParseException spex)
throws SAXException {
// output error and exit
spex.printStackTrace();
System.exit(0);
}
public void error(SAXParseException spex)
throws SAXParseException {
// output error and continue
spex.printStackTrace();
}
public void warning(SAXParseException spex)
throws SAXParseException {
// output warning and continue
spex.printStackTrace();
}
});
// Read the document
URL url = new URL(ValidateWithExternalDTD.URL);
Document xmlDocument = builder.parse(url.openStream());
DOMSource source = new DOMSource(xmlDocument);
// Use the tranformer to validate the document
StreamResult result = new StreamResult(System.out);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, ValidateWithExternalDTD.DTD);
transformer.transform(source, result);
// Process your document if everything is OK
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
Another way would be to replace the XML title with the XML title plus the DTD reference
Replace this:
<?xml version = "1.0"?>
with this:
<?xml version = "1.0"?><!DOCTYPE ...>
Of course you would replace the first occurance only and not try to go through the whole xml document
You have to instantiate the SAXBuilder by passing true(validate) to its constructor:
SAXBuilder builder = new SAXBuilder(true);
or call:
builder.setValidation(true)
In an open source project I maintain, we have at least three different ways of reading, processing and writing XML files and I would like to standardise on a single method for ease of maintenance and stability.
Currently all of the project files use XML from the configuration to the stored data, we're hoping to migrate to a simple database at some point in the future but will still need to read/write some form of XML files.
The data is stored in an XML format that we then use a XSLT engine (Saxon) to transform into the final HTML files.
We currently utilise these methods:
- XMLEventReader/XMLOutputFactory (javax.xml.stream)
- DocumentBuilderFactory (javax.xml.parsers)
- JAXBContext (javax.xml.bind)
Are there any obvious pros and cons to each of these?
Personally, I like the simplicity of DOM (Document Builder), but I'm willing to convert to one of the others if it makes sense in terms of performance or other factors.
Edited to add:
There can be a significant number of files read/written when the project runs, between 100 & 10,000 individual files of around 5Kb each
It depends on what you are doing with the data.
If you are simply performing XSLT transforms on XML files to produce HTML files then you may not need to touch a parser directly:
import java.io.File;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
TransformerFactory tf = TransformerFactory.newInstance();
StreamSource xsltTransform = new StreamSource(new File("xslt.xml"));
Transformer transformer = tf.newTransformer(xsltTransform);
StreamSource source = new StreamSource(new File("source.xml"));
StreamResult result = new StreamResult(new File("result.html"));
transformer.transform(source, result);
}
}
If you need to make changes to the input document before you transform it, DOM is a convenient mechanism for doing this:
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
public class Demo {
public static void main(String[] args) throws Exception {
TransformerFactory tf = TransformerFactory.newInstance();
StreamSource xsltTransform = new StreamSource(new File("xslt.xml"));
Transformer transformer = tf.newTransformer(xsltTransform);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(new File("source.xml"));
// modify the document
DOMSource source = new DOMSource(document);
StreamResult result = new StreamResult(new File("result.html"));
transformer.transform(source, result);
}
}
If you prefer a typed model to make changes to the data then JAXB is a perfect fit:
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.util.JAXBSource;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
TransformerFactory tf = TransformerFactory.newInstance();
StreamSource xsltTransform = new StreamSource(new File("xslt.xml"));
Transformer transformer = tf.newTransformer(xsltTransform);
JAXBContext jc = JAXBContext.newInstance("com.example.model");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Model model = (Model) unmarshaller.unmarshal(new File("source.xml"));
// modify the domain model
JAXBSource source = new JAXBSource(jc, model);
StreamResult result = new StreamResult(new File("result.html"));
transformer.transform(source, result);
}
}
This is a very subjective topic. It primarily depends on how you are going to use the xml and size of XML. If XML is (always) small enough to be loaded in to memory, then you don't have to worry about memory foot print. You can use DOM parser. If you need to a parse through 150 MB xml you may want to think of using SAX. etc.
Java, Xerces 2.9.1
insertHere.setAttributeNS(XMLConstants.XML_NS_URI, "xml:space", "preserve");
and
insertHere.setAttributeNS(XMLConstants.XML_NS_URI, "space", "preserve")
both end up with an attribute of just space='preserve', no XML prefix.
insertHere.setAttribute( "xml:space", "preserve")
works, but it seems somehow wrong. Am I missing anything?
EDIT
I checked.
I read a template document in with setNamespaceAware turned on.
I then use the following to make a copy of it, and then I start inserting new elements.
public static Document copyDocument(Document input) {
DocumentType oldDocType = input.getDoctype();
DocumentType newDocType = null;
Document newDoc;
String oldNamespaceUri = input.getDocumentElement().getNamespaceURI();
if (oldDocType != null) {
// cloning doctypes is 'implementation dependent'
String oldDocTypeName = oldDocType.getName();
newDocType = input.getImplementation().createDocumentType(oldDocTypeName,
oldDocType.getPublicId(),
oldDocType.getSystemId());
newDoc = input.getImplementation().createDocument(oldNamespaceUri, oldDocTypeName,
newDocType);
} else {
newDoc = input.getImplementation().createDocument(oldNamespaceUri,
input.getDocumentElement().getNodeName(),
null);
}
Element newDocElement = (Element)newDoc.importNode(input.getDocumentElement(), true);
newDoc.replaceChild(newDocElement, newDoc.getDocumentElement());
return newDoc;
}
When I run the following code:
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class Demo {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.newDocument();
Element rootElement = document.createElement("root");
document.appendChild(rootElement);
rootElement.setAttributeNS(XMLConstants.XML_NS_URI, "space", "preserve");
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.transform(new DOMSource(document), new StreamResult(System.out));
}
}
I get the following output:
<root xml:space="preserve"/>
How are you building your document?