I want to create a XML from a template during runtime in Java using JDOM.
Below is a sample template
<PARENT>
<ISSUES>
<ISSUE id="ISSUE-X">
<SUMMARY></SUMMARY>
<CATEGORY></CATEGORY>
..
</ISSUE>
</ISSUES>
</PARENT>
I want to load this template file using Java + JDOM and get the following
<PARENT>
<ISSUES>
<ISSUE id="ISSUE-1">
<SUMMARY>Test 1</SUMMARY>
<CATEGORY>Cat 1</CATEGORY>
..
</ISSUE>
<ISSUE id="ISSUE-2">
<SUMMARY>Test 2</SUMMARY>
<CATEGORY>Cat 2</CATEGORY>
..
</ISSUE>
</ISSUES>
</PARENT>
Ideally I want to create more ISSUE nodes and fill the data from DB & save to file
Reason I thought I could use Template is because there will be additional nodes under <ISSUE> which I need to fill from db & was thinking filling this via template would be much faster
Can someone guide me on how to get this done in Java using JDOM?
Note: This template will adhere to a XSD which I haven't given here.
Thanks in advance
EDIT: Code snippet below
String sXMLPath = "D:\\WS\\issue_sample.xml";
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder;
dBuilder = dbFactory.newDocumentBuilder();
org.w3c.dom.Document doc = dBuilder.parse(new File(sXMLPath));
DOMBuilder domBuilder = new DOMBuilder();
Document xConfigurationDocument;
xConfigurationDocument = domBuilder.build(doc);
XPathFactory xpfac = XPathFactory.instance();
XPathExpression<Element> xElements = xpfac.compile("//ns:MY-ISSUE/ns:ISSUES",Filters.element(),null,Namespace.getNamespace("ns", "http://www.myns.net/schemas/issue"));
List<Element> elements = xElements.evaluate(xConfigurationDocument);
for (Element xIssuesParent : elements) {
System.out.println(xIssuesParent.getName());
Element xCloneIssue = null ;
for (Element xIssueChild : xIssuesParent.getChildren())
{
xCloneIssue = xIssueChild.clone();
System.out.println(xIssueChild.getName());
xIssuesParent.removeContent(xIssueChild);
}
for (int i = 1; i < 3; i++) {
xCloneIssue.setAttribute("ID", "ISSUE-" + i);
xIssuesParent.addContent(xCloneIssue);
}
}
XMLOutputter xmlOutput = new XMLOutputter();
// display nice nice
xmlOutput.setFormat(Format.getPrettyFormat());
xmlOutput.output(xConfigurationDocument, new FileWriter("c:\\temp\\OutputFile.xml"));
I am trying out this in a sample application
The problem I face is that in the for loop (for (int i = 1; i < 3; i++)) after 1st I always get the following error The Content already has an existing parent "ISSUES"
Obviously what I am missing is a new clone.
My question is how can i always get a handle of an element and keep adding to the parent
If it will adhere to an XSD then take a look at org.jdom.input.DOMBuilder which you can parse a DTD into.
Related
I am trying to get all arrays I store in: https://s3.eu-west-2.amazonaws.com/tekstpieprz/strings.xml
I would like to use them for my textviews. I have added Unirest but cannot get my head around JSON. I have tried to play with something like:
HttpResponse<JsonNode> request = (HttpResponse<JsonNode>) Unirest.get("https://s3.eu-west-2.amazonaws.com/tekstpieprz/strings.xml")
.getBody("docukrz");
JSONObject myObj = request.getBody().getObject();
final JSONArray results = myObj.getJSONArray(String docukrz);
so then I can use the array in:
final String[] docukrz = res.getStringArray(R.array.docukrz);
But instead using
Resources
I would like to use the array I store online.
I do not fully understand how JSON works, I have only started learning JAVA 6 weeks ago. Any help would be much much appreciated.
You can find XML prase example here How can I parse xml from url in android?.
according to that answer, your code should be like below
URL url = new URL("https://s3.eu-west-2.amazonaws.com/tekstpieprz/strings.xml");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new InputSource(url.openStream()));
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getElementsByTagName("docukrz");
ArrayList resourceList = new ArrayList();
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
resourceList.add(node);
}
I need to find the easier and the efficient way to convert a JDOM element (with all it's tailoring nodes) to a Document. ownerDocument( ) won't work as this is version JDOM 1.
Moreover, org.jdom.IllegalAddException: The Content already has an existing parent "root" exception occurs when using the following code.
DocumentBuilderFactory dbFac = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFac.newDocumentBuilder();
Document doc = null;
Element elementInfo = getElementFromDB();
doc = new Document(elementInfo);
XMLOutputter xmlOutput = new XMLOutputter();
byte[] byteInfo= xmlOutput.outputString(elementInfo).getBytes("UTF-8");
String stringInfo = new String(byteInfo);
doc = dBuilder.parse(stringInfo);
I think you have to use the following method of the element.
Document doc = <element>.getDocument();
Refer the API documentation It says
Return this parent's owning document or null if the branch containing this parent is currently not attached to a document.
JDOM content can only have one parent at a time, and you have to detatch it from one parent before you can attach it to another. This code:
Document doc = null;
Element elementInfo = getElementFromDB();
doc = new Document(elementInfo);
if that code is failing, it is because the getElementFromDB() method is returning an Element that is part of some other structure. You need to 'detach' it:
Element elementInfo = getElementFromDB();
elementInfo.detach();
Document doc = new Document(elementInfo);
OK, that solves the IllegalAddException
On the other hand, if you just want to get the document node containing the element, JDOM 1.1.3 allows you to do that with getDocument:
Document doc = elementInfo.getDocument();
Note that the doc may be null.
To get the top most element available, try:
Element top = elementInfo;
while (top.getParentElement() != null) {
top = top.getParentElement();
}
In your case, your elementInfo you get from the DB is a child of an element called 'root', something like:
<root>
<elementInfo> ........ </elementInfo>
</root>
That is why you get the message you do, with the word "root" in it:
The Content already has an existing parent "root"
I have a large SOAP response that I want to process and store in Database. I'm trying to process the whole thing as Document as below
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setCoalescing(true);
DocumentBuilder db = dbf.newDocumentBuilder();
InputStream is = new ByteArrayInputStream(resp.getBytes());
Document doc = db.parse(is);
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile(fetchResult);
String result = (String) expr.evaluate(doc, XPathConstants.STRING);
resp is the SOAP response and fetchResult is
String fetchResult = "//result/text()";
I'm getting out of memory exception with this approach. So I was trying to process the document as a stream, rather than consuming the entire response as a Document.
But I can not come up with the code.
Could any of you please help me out?
DOM & JDOM are memory-consuming parsing APIs. DOM creates a tree of the XML document in memory. You should use StAX or SAX because they offer better performance.
If this in Java you could try using dom4j. This has a nice way of reading the xml using the xpathExpression.
Additionally dom4j provides an event based model for processing XML documents. Using this event based model allows us to prune the XML tree when parts of the document have been successfully processed avoiding having to keep the entire document in memory.
If you need to process a very large XML file that is generated externally by some database process and looks something like the following (where N is a very large number).
<ROWSET>
<ROW id="1">
...
</ROW>
<ROW id="2">
...
</ROW>
...
<ROW id="N">
...
</ROW>
</ROWSET>
So to process each <ROW> individually you can do the following.
// enable pruning mode to call me back as each ROW is complete
SAXReader reader = new SAXReader();
reader.addHandler( "/ROWSET/ROW",
new ElementHandler() {
public void onStart(ElementPath path) {
// do nothing here...
}
public void onEnd(ElementPath path) {
// process a ROW element
Element row = path.getCurrent();
Element rowSet = row.getParent();
Document document = row.getDocument();
...
// prune the tree
row.detach();
}
}
);
Document document = reader.read(url);
// The document will now be complete but all the ROW elements
// will have been pruned.
// We may want to do some final processing now
...
Please see How dom4j handle very large XML documents? to understand how it works.
Moreover dom4j works with any SAX parser via JAXP.
For more details see What XML parser does dom4j use?
The XPath & XPathExpression classes have methods that accept an InputSource argument.
InputStream input = ...;
InputSource source = new InputSource(input);
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile("...");
String result = (String) expr.evaluate(source, XPathConstants.STRING);
I'm writing a tool to transform CSV formatted data into XML. The user will specify the parsing method and that is: the XSD for the output, which field in the CSV goes in which field of the resulting XML.
(very simplified use-case) Example:
CSV
Ciccio;Pippo;Pappo
1;2;3
XSD
(more stuff...)
<xs:element name="onetwo">
<xs:element name="three">
<xs:element name="four">
USER GIVES RULES
Ciccio -> onetwo
Pippo -> three
Pappo -> four
I've implemented this in C# using Dataset, how could I do it in Java? I know there's DOM, JAXB etc. but it seems XSD is only used to validate an otherwise created XML. Am I wrong?
Edit:
Everything needs to be at runtime. I don't know what kind of XSD I'll receive so I cannot instantiate objects that don't exist nor populate them with data. So I'm guessing the xjc is not an option.
Since you have the XSD for your output XML file, the best way to create this XML would be by using Java Architecture for XML Binding (JAXB). You might want to refer to: "Using JAXB" tutorial to give you an overview of how to go about using this for your requirement.
The basic idea is as follows:
Generate JAXB Java classes from an XML schema, i.e. the XSD that you have
Use schema-derived JAXB classes to unmarshal and marshal XML content in a Java application
Create a Java content tree from scratch using schema-derived JAXB classes
Unmarshal the data to your output XML file.
Here's another tutorial that you might find informative.
This is still work in progress, but you could recurse over the XSD writing out elements as you find them to a new document tree.
public void run() throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new FileReader(
"schema.xsd")));
Document outputDoc = builder.newDocument();
recurse(document.getDocumentElement(), outputDoc, outputDoc);
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
StringWriter buffer = new StringWriter();
transformer.transform(new DOMSource(outputDoc),
new StreamResult(buffer));
System.out.println(buffer.toString());
}
public void recurse(Node node, Node outputNode, Document outputDoc) {
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
if ("xs:element".equals(node.getNodeName())) {
Element newElement = outputDoc.createElement(element
.getAttribute("name"));
outputNode = outputNode.appendChild(newElement);
// map elements from CSV values here?
}
if ("xs:attribute".equals(node.getNodeName())) {
//TODO required attributes
}
}
NodeList list = node.getChildNodes();
for (int i = 0; i < list.getLength(); i++) {
recurse(list.item(i), outputNode, outputDoc);
}
}
I have an XML file that I am trying to search using Java. I just need to find an element by its Tag name and then find that Tag's value. So for example:
I have this XML file:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="https://company.com/test/xslt/processing_report.xslt"?>
<Certificate xmlns="urn:us:net:exchangenetwork:Company">
<Value1>Veggie</Value1>
<Value2>Fruits</Value2>
<type1>Apple</type1>
<FindME>Red</FindME>
<Value3>Bread</Value3>
</Certificate>
I want to find the value inside of the FindME Tag. I can't use XPath because different files can have different structures, but they always have a FindME tag. Lastly I am looking for the simplest piece of code, I do not care much about performance. Thank you
Here is the code:
XPathFactory f = XPathFactory.newInstance();
XPathExpression expr = f.newXPath().compile(
"//*[local-name() = 'FindME']/text()");
DocumentBuilderFactory domFactory = DocumentBuilderFactory
.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("src/test.xml"); //your XML file
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
System.out.println(nodes.getLength());
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
Explained :
//* - match any element node - no matter where they are
local-name() = 'FindME' - where local name - i.e; not the full path - matches 'FindME'
text() - get the node value.
I think you need to read up on XPath because it can very easily solve this problem. So can using getElementsByTagName in the DOM API.
You can still use XPath. All you need to do is use //FindMe (read here on // usage) expression. This finds a the "FindMe" elements from any where in the xml irrespective of its parent or path from the root.
If you are using namespaces then make sure you are making the parser aware of that
String findMeVal = null;
InputStream is = //...
XmlPullParser parser = //...
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(is, null);
int event;
while (XmlPullParser.END_DOCUMENT != (event = parser.next())) {
if (event == XmlPullParser.START_TAG) {
if ("FindME".equals(parser.getName())) {
findMeVal = parser.nextText();
break;
}
}
}