I have the following code which turns a string, that I pass into the function, into a document:
DocumentBuilderFactory dbFactory_ = DocumentBuilderFactory.newInstance();
Document doc_;
void toXml(String s)
{
documentBuild();
DocumentBuilder dBuilder = dbFactory_.newDocumentBuilder();
StringReader reader = new StringReader(s);
InputSource inputSource = new InputSource(reader);
doc_ = dBuilder.parse(inputSource);
}
The problem is that some of the legacy code that I'm using passes into this toXml function a single word like RANDOM or FICTION. I would like to turn these calls into valid xml before trying to parse it. Right now if I call the function with s = FICTION it returns a SAXParseExeption error. Could anyone advise me on the right way to do this? If you have any questions let me know.
Thank you for your time
-Josh
This creates an XmlDocument with an element test
function buildXml(string s) {
XmlDocument d = new XmlDocument();
d.AppendChild(d.CreateElement(s));
StringWriter sw = new StringWriter();
XmlTextWriter xw = new XmlTextWriter(sw);
d.WriteTo(xw);
return sw.ToString();
}
buildXml("Test"); //This will return <Test />
Its a bit ugly but it will create the XML without having to do any string work on your own ;)
You could add this in a try catch in your method so if it fails to load it as an XML directly it passes the string to this and then tries to load it.
Have you tried the seemingly obvious <FICTION/> or <FICTION></FICTION>?
Related
i'm trying to write the header for an xml file so it would be something like this:
<file xmlns="http://my_namespace"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://my_namespace file.xsd">
however, I can't seem to find how to do it using the Document class in java. This is what I have:
public void exportToXML() {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
try {
dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.newDocument();
doc.setXmlStandalone(true);
doc.createTextNode("<file xmlns=\"http://my_namespace"\n" +
"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
"xsi:schemaLocation=\"http://my_namespace file.xsd\">");
Element mainRootElement = doc.createElement("MainRootElement");
doc.appendChild(mainRootElement);
for(int i = 0; i < tipoDadosParaExportar.length; i++) {
mainRootElement.appendChild(criarFilhos(doc, tipoDadosParaExportar[i]));
}
Transformer tr = TransformerFactory.newInstance().newTransformer();
tr.transform(new DOMSource(doc),
new StreamResult(new FileOutputStream(filename)));
} catch (Exception e) {
e.printStackTrace();
}
}
I tried writing it on the file using the createTextNode but it didn't work either, it only writes the version before showing the elements.
PrintStartXMLFile
Would appreciate if you could help me. Have a nice day
Your createTextNode() method is only suitable for creating text nodes, it's not suitable for creating elements. You need to use createElement() for this. If you're doing this by building a tree, then you need to build nodes, you can't write lexical markup.
I'm not sure what MainRootElement is supposed to be; you've only given a fragment of your desired output so it's hard to tell.
Creating a DOM tree and then serializing it is a pretty laborious way of constructing an XML file. Using something like an XMLEventWriter is easier. But to be honest, I got frustrated by all the existing approaches and wrote a new library for the purpose as part of Saxon 10. It's called simply "Push", and looks something like this:
Processor proc = new Processor();
Serializer serializer = proc.newSerializer(new File(fileName));
Push push = proc.newPush(serializer);
Document doc = push.document(true);
doc.setDefaultNamespace("http://my_namespace");
Element root = doc.element("root")
.attribute(new QName("xsi", "http://www.w3.org/2001/XMLSchema-instance", "schemaLocation"),
"http://my_namespace file.xsd");
doc.close();
Consider the code fragment that I have at the moment which works and the right elements are found and placed into my map:
public void importXml(InputSource emailAttach)throws Exception {
Map<String, String> hWL = new HashMap<String, String>();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(emailAttach);
FileOutputStream fos=new FileOutputStream("temp.xml");
OutputStreamWriter os = new OutputStreamWriter(fos,"UTF-8");
// Transform to XML UTF-8 format
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.transform(new DOMSource(doc), new StreamResult(os));
os.close();
fos.close();
doc = db.parse(new File("temp.xml"));
NodeList nl = doc.getElementsByTagName("Email");
Element eE=(Element)nl.item(0);
int ctr=eE.getChildNodes().getLength();
String sNName;
String sNValue;
Node nTemp;
for (int i=0;i<ctr;i++){
nTemp=eE.getChildNodes().item(i);
sNName=nTemp.getNodeName().toUpperCase().trim();
if (nTemp.getChildNodes().item(0)!=null) {
sNValue=nTemp.getChildNodes().item(0).getNodeValue().trim();
hWL.put(sNName,sNValue);
}
}
}
However I prefer not to create a temp file first after converting the data to UTF-8 and parsing from the temp file. Is there anyway I can do this?
I've tried using a ByteArrayOutputStream in place of OutputStreamWriter, and calling toString() on the ByteArrayOutputStream as such:
doc = db.parse(bos.toString("UTF-8");
But then my Map ends up being empty.
From the API docs (the ability of its meticulous studying is a valuable asset for any programmer) - the parse method with the String argument seems to take something different from what you feed to it:
Document parse(String uri)
Parse the content of the given URI as an XML document and return a new DOM >Document object.
This might be your friend:
db.parse ( new ByteArrayInputStream( bos.toByteArray()));
Update
#user2496748 sorry I should have searched for the API but instead I was looking at the source code through a decompiler which tells me the parameter is arg0 instead of uri. Big difference.
I think I understand stream readers/writers and byte to char or vice versa a little more now.
After some review I was able to simply my code to this and achieve what I wanted to do. Since I am able to get the email attachment as a InputSource:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
emailAttach.setEncoding("UTF-8");
Document doc = db.parse(emailAttach);
Works as well and tested with non-english characters.
You don't need to write and re-read and re-parse the transformed document. Just change this:
t.transform(new DOMSource(doc), new StreamResult(os));
to this:
DOMResult result = new DOMResult();
t.transform(new DOMSource(doc), result);
doc = (Document)result.getNode();
and then continue from after your present doc = db.parse(new File("temp.xml"));.
I'm using XMLStreamReader to parse a piece of xml:
XMLStreamReader rd = XMLInputFactory.newInstance().createXMLStreamReader(io_xml, "UTF-8");
...
if (eventType == XMLStreamConstants.START_ELEMENT) {
String name = rd.getLocalName();
if (name.equals("key")) {
String val = rd.getElementText();
}
}
Problem is, I'm getting a bad read for the following string: "<key>cami%C3%B5es%2Babc</key>"
org.junit.ComparisonFailure:
expected:<cami[%C3%B5es%]2Babc> but was:<cami[ C3 B5es ]2Babc>
Do I neeed to do anything special within the XML? I already tried to put everything within a CDATA section but I get the same error.
Using a "regular" parser everything works:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
InputSource is = new InputSource(new StringReader(xml));
Document parse = builder.parse(is);
String value = parse.getFirstChild().getTextContent();
...
I figured it out. The problem was in a different section of the code. A setter that didn't just set.
I have a string object "hello world"
I need to create an xml file from this string with hello world as text content.
I tried the following code snippet
String xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"></soap:Envelope>";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
try
{
builder = factory.newDocumentBuilder();
// Use String reader
Document document = builder.parse( new InputSource(
new StringReader( xmlString) ) );
TransformerFactory tranFactory = TransformerFactory.newInstance();
Transformer aTransformer = tranFactory.newTransformer();
Source src = new DOMSource( document );
Result dest = new StreamResult( new File("D:\\myXML.xml" ) );
aTransformer.transform( src, dest );
} catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
this code works fine. but when i replace the string with "Hello world" its not working.
Can any one help me out in this ?
Thanks
You cannot turn the string "hello world" into XML, as it is not a valid xml document. It has no declaration, and no tags.
The code above will not turn text into xml objects, it will only take a string which is already valid xml and write it out to file.
To be honest, if you just want to write it to a file, the xml stuff is all unnecessary.
If you want some kind of "hello world" xml file, you'll need to add the declaration and some tags yourself.
This error is because you are trying to parse xmlString as a valid XML string, which it is not. For example, your code will run fine with the following xmlString:
String xmlString = "<hi>Hello World</hi>";
If you have String newNode = "<node>Hello World</node>";
You can use
Element node = DocumentBuilderFactory
.newInstance()
.newDocumentBuilder()
.parse(new ByteArrayInputStream(newNode.getBytes()))
.getDocumentElement();
The simplest solution can be here is:
If it's a valid string(correct as per XML norms) just write it into a new file using FileWriter and give it .xml extension.
Anyway it will not convert if it's not a valid XML string
I have a string as below.
<employees>
<emp>
<name>yaakobu</name>
<sal>$20000</sal>
<designation>Manager</designation>
</emp>
<emp>
<name>daaniyelu</name>
<sal>$2000</sal>
<designation>Operator</designation>
</emp>
<emp>
<name>paadam</name>
<sal>$7000</sal>
<designation>Engineer</designation>
</emp>
</employees>
The above xml i am getting as a string.i was asked not to use parsing due to performance issue.I need to get the second employee 's salary($2000) using java's string operation.Please provide me some pointers.
Your help appreciated.
Your string is xml.
Although it might be tempting to use regex or other string manipulation to extract data from xml - don't do it - it's a bad practice.
You should use some XML parser instead.
After you've done this using your string operations, give the following a try:
import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.xpath.*;
public class Main {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("test.xml");
XPath xpath = XPathFactory.newInstance().newXPath();
// get the salary from the employee at index 1
XPathExpression expr = xpath.compile("//emp[1]/sal");
Object salary = expr.evaluate(doc, XPathConstants.STRING);
System.out.println(salary);
}
}
which should output:
$20000
I'm not guaranteeing it will be faster, but it won't differ all that much I think. And doing it like this will be far less fragile than doing this with indexOf(...) and substring(...) calls.
I doubt there will be performance issues using an xml parser, but if you want to do it by string parsing, use str.indexOf("<sal>", str.indexOf("<sal>") + 5); Then it will be easy.
Use xml parser or JAXB api for unmarshal the String into object, you can do it through this way also.
private static Object getObject(String yourXml) throws Exception {
JAXBContext jcUnmarshal = null;
Unmarshaller unmarshal = null;
javax.xml.stream.XMLStreamReader rdr = null;
//Object obj = null;
try {
jcUnmarshal = JAXBContext.newInstance("com.test.dto");
unmarshal = jcUnmarshal.createUnmarshaller();
rdr = javax.xml.stream.XMLInputFactory.newInstance().createXMLStreamReader(new StringReader(yourXml));
//obj = (Object) unmarshal.unmarshal(rdr);
return (Object) unmarshal.unmarshal(rdr);
} catch (JAXBException jaxbException) {
jaxbException.printStackTrace();
log.error(jaxbException);
throw new ServiceException(jaxbException.getMessage());
}
finally{
jcUnmarshal = null;
unmarshal = null;
rdr.close();
rdr = null;
}
//return obj;
}
you might use xstream
http://x-stream.github.io/
you put your xml in an object structure and get it from there.
check the samples ,is very easy to use
This if you don't want to parse yourself...:)