Unmarshal xml List Using xstream without setting aliases - java

I'm trying to unmarshal an xml document that contains lists of composite elements. Is it possible to do this without having to set the aliases individually for the list and the composit element.
the xml I'm consuming looks something like this:
<Library>
<Books>
<Book>
<author>author1</author>
<title>title1</title>
</Book>
<Book>
<author>author2</author>
<title>title2</title>
</Book>
</Books>
<!-- other things here -->
</Library>
I have made the appropriate classes to correctly model the data
and using xstream
XStream stream = new XStream();
stream.alias("Library",Library.class);
stream.alias("Book",Book.class);
stream.alias("Books",List.class);
Library lib = stream.fromXML(xml);
I am trying to avoid having to alias book to book.class and books to list.class
is this even possible or do I need to find a workaround of some sort?

Related

Can I get to an index of parsed XML using XStream

I am using XStream library for XML parsing. I was wondering if the library allows jumping to a particular node directly using the index.
So for e.g.
<details>
<personal>
<basicInfo>
<firstName>John</firstName>
<lastName>Doe</lastName>
<phoneNumber>9999999999</phoneNumber>
<dateOfBirth>1990-01-01</dateOfBirth>
</basicInfo>
<address>
<street>random St.</street>
<city>City</city>
<stateProv>BC</stateProv>
<country>CA</country>
<postCode>12345</postCode>
</address>
</personal>
<personal>
<basicInfo>
<firstName>John2</firstName>
<lastName>Doe2</lastName>
<phoneNumber>9999999999</phoneNumber>
<dateOfBirth>1990-01-01</dateOfBirth>
</basicInfo>
<address>
<street>random St.2</street>
<city>City2</city>
<stateProv>BC2</stateProv>
<country>CA2</country>
<postCode>12345</postCode>
</address>
</personal>
</details>
For the XML above I would like to skip the first <personal>...</personal>
and only process the second node. Can I call it using an index.
XStream is a simple library to serialize objects to XML and back again.
I am not sure what you mean by process in this context, but if your POJO for serialization is set up correctly to contain a List of "personal" nodes. I don't see why you couldn't deserialize the XML and remove the unwanted node after the fact.
As far as I know, vtd-xml is the only XML parsing routine that natively offers indexing feature, called vtd+XML.

Generic xpath for a node at different locations

I have a lot of xml files from different versions of schemas. There are certain sections/tags in these xmls that are the same.
What I want to do is locate a perticular tag and start processing that tag. The thing is that this tag may appear at different locations in the xml.
So I am looking for a xpath that will locate this node irrespective of its location. I am using Java for writing my processing code.
Following are the various falvours of the xmls
Sample 1
<nodeIWant>
<book>
<title>Harry Potter and the Philosophers Stone</title>
...
</book>
</nodeIWant>
Sample 2
<a>
<nodeIWant>
<book>
<title>Harry Potter and the Philosophers Stone</title>
...
</book>
</nodeIWant>
</a>
Sample 3
<b>
<nodeIWant>
<book>
<title>Harry Potter and the Philosophers Stone</title>
...
</book>
</nodeIWant>
</b>
In the above xmls I want to use the same xpath to locate the node 'nodeIWant'.
The Java code I am using is the following
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = factory.newDocumentBuilder();
Document modelDoc = docBuilder.parse(args[0]);
XPath xPath = XPathFactory.newInstance().newXPath();
System.out.println(xPath.evaluate("//nodeIWant", modelDoc.getDocumentElement(), XPathConstants.NODE));
This prints out a null.
Final Edit
The answer by Mathias Müller works for these xml files. I am actually trying to query the .emx files in Rational Software Architect. I was trying to avaoid using these for examples. (Please don't start talking about BIRT and using the eclipse uml APIs etc... I have tried these and they do not give me what I want.)
The structure of the files is the following
<?xml version="1.0" encoding="UTF-8"?>
<!--xtools2_universal_type_manager-->
<?com.ibm.xtools.emf.core.signature <signature id="com.ibm.xtools.uml.msl.model" version="7.0.0"><feature description="" name="com.ibm.xtools.ruml.feature" url="" version="7.0.0"/></signature>?>
<?com.ibm.xtools.emf.core.signature <signature id="com.ibm.xtools.mmi.ui.signatures.diagram" version="7.0.0"><feature description="" name="Rational Modeling Platform (com.ibm.xtools.rmp)" url="" version="7.0.0"/></signature>?>
<xmi:XMI version="2.0" xmlns:Default="http:///schemas/Default/_fNm3AAqoEd6-N_NOT9vsCA/2" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:uml="http://www.eclipse.org/uml2/3.0.0/UML" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http:///schemas/Default/_fNm3AAqoEd6-N_NOT9vsCA/2 pathmap://UML2_MSL_PROFILES/Default.epx#_fNwoAAqoEd6-N_NOT9vsCA?Default/Default?">
<uml:Model name="A" xmi:id="_4lzSsMywEeGAuoBpYhfj6Q">
<!-- Lot of other stuff -->
</uml:Model>
<xmi:XMI>
The other file is
<?xml version="1.0" encoding="UTF-8"?>
<!--xtools2_universal_type_manager-->
<?com.ibm.xtools.emf.core.signature <signature id="com.ibm.xtools.uml.msl.model" version="7.0.0"><feature description="" name="com.ibm.xtools.ruml.feature" url="" version="7.0.0"/></signature>?>
<?com.ibm.xtools.emf.core.signature <signature id="com.ibm.xtools.mmi.ui.signatures.diagram" version="7.0.0"><feature description="" name="Rational Modeling Platform (com.ibm.xtools.rmp)" url="" version="7.0.0"/></signature>?>
<uml:Model xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:uml="http://www.eclipse.org/uml2/3.0.0/UML" xmi:id="_4lzSsMywEeGAuoBpYhfj6Q" name="A">
<!-- Lot of other stuff -->
</uml:Model>
Shouldn't the xpath of '//Model' work for these two samples as well?
You can use the xPath 'axis' //. This searches in the file for your node and doesn't care about the parent-nodes. So in your example you can use:
//nodeIWant
Not very familiar with DocumentBuilder, but perhaps you need to compile an XPath expression before evaluating it against a document? It seems it's not XPath expressions that are evaluated, XML documents are.
String expression = "//nodeIWant";
NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(modelDoc, XPathConstants.NODESET);
Or, if there is just one of those elements and you'd like to print its string value:
String expression = "//nodeIWant";
System.out.println(xPath.compile(expression).evaluate(modelDoc));
EDIT: You edited your question and revealed the actual XML you are evaluating path expressions against. Those new documents have namespaces that you need to take into account in XPath expressions.
//nodeIWant will never find a node if it is actually in a namespace. To find the Model node in your new documents, you'd have to use
//*[local-name() = 'Model']
Since the example you provided contains more than just a String in the <nodeIWant> elements you probably can benefit from using an object oriented approach combined with xpath. With data projection (disclosure: I'm affiliated with that project) it's possible to do this:
public class DataProjection {
public interface Book {
#XBRead("./title")
String getTitle();
//... more getter or setter methods
}
public static void main(String[] args) {
// Print all books in all <nodeIWant> elements of
for (String file : new String[] { "a.xml", "b.xml", "c.xml" }) {
List<Book> books = new XBProjector().io().file(file).evalXPath("//nodeIWant/book").asListOf(Book.class);
for (Book book : books) {
System.out.println(book.getTitle());
}
}
}
}
You can define one or more views (called projection interfaces) to the XML data and use XPath to connect the data to java objects implementing these interfaces. This helps a lot in structuring your code and have it reuseable for similar XML files.

Is it possible to create an object from XML file using DOM?

I use DOM parser to read data from XML file. I know how to read, modify and write back the data. However, I would like to know if it is possible to create an object from an XML file.
I have an XML file which looks like this:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE people SYSTEM "validator.dtd">
<people>
<student>
<name>John</name>
<course>Computer Technology</course>
<semester>6</semester>
<scheme>E</scheme>
</student>
<student>
<name>Foo</name>
<course>Industrial Electronics</course>
<semester>6</semester>
<scheme>E</scheme>
</student>
</people>
and I would like to make it an objects out of it so I can pass them around. Does a solution exist ?
Yes. This is possible through JAXB (Java API for XML binding)
All JAXB implementations provide a tool called a binding compiler to bind a XML schema in order to generate the corresponding Java classes.
For details refer: http://www.oracle.com/technetwork/articles/javase/index-140168.html#xmp1
You could have a look at XML beans or JAXB libraries. In case you don't have a schema file but have a sample XML file, you could create one using inst2xsd tool of xmlbeans. http://xmlbeans.apache.org/docs/2.0.0/guide/tools.html. This could get you started with the schema.

JAXB Vs JDOM : is it possible to update xml file using JAXB

i have been used JDOM to perform xml data entry & updation in any XML file, but now i am trying to use JAXB instead of JDOM but getting some difficulties.
as i know marshalling & unmarshalling in jaxb but when it comes to entry a new data into a xml at specified location (node), i find difficulties. e.g. for new entry Japan where id = Asia
<file>
<parent>
<node id="Asia">
<name>India</name>
<name>China</name>
</node>
<node id="Europe">
<name>UK</name>
</node>
</parent>
</file>
is there anybody who has idea about it.
If I'm not mistaken JAXB and JDOM and completely different things. JAXB will serialize java objects into an XML format and vice versa. JDOM simply reads in the XML file and stores it in a DOM tree which can then be used to modify the xml itself.
Using JAXB in this way is like trying to at runtime add a new variable to a class. It cannot be done. (at least to my knowledge).

How can I do type-safe Xpath queries in Java?

I'm currently using JDOM for doing some simple XML parsing, and it seems like nothing's type safe - I had a similar issue with using the built-in Java DOM parser, just with lots more API to wade through.
For example, XPath.selectNodes takes an Object as its argument and returns a raw list, which just feels a little Java 1.1
Are there generic-ized XML and XPath libraries for Java, or is there some reason why it's just not possible to do XPath queries in a type-safe way?
If you're familiar with CSS selectors on HTML, it may be good to know that Jsoup supports XML as well.
Update: OK, that was given the downvote apparently a very controversial answer. It may however end up to be easier and less verbose than Xpath when all you want is to select node values. The Jsoup API is namely very slick. Let's give a bit more concrete example. Assuming that you have a XML file which look like this:
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person id="1">
<name>John Doe</name>
<age>30</age>
<address>
<street>Main street 1</street>
<city>Los Angeles</city>
</address>
</person>
<person id="2">
<name>Jane Doe</name>
<age>40</age>
<address>
<street>Park Avenue 1</street>
<city>New York</city>
</address>
</person>
</persons>
Then you can traverse it like follows:
Document document = Jsoup.parse(new File("/persons.xml"), "UTF-8");
Element person2 = document.select("person[id=2]").first();
System.out.println(person2.select("name").text());
Elements streets = document.select("street");
for (Element street : streets) {
System.out.println(street.text());
}
which outputs
Jane Doe
Main street 1
Park Avenue 1
Update 2: since Jsoup 1.6.2 which was released March 2012, XML parsing is officially supported by the Jsoup API.
AFAIK all of the xml queries in java are non-typesafe and most are java 1.3 compatible. That said my favorite parser/generator is the xml pull parser (xmlpp) style parser. I believe java has XmlStreamReader and XmlStreamWriter if you're using 1.6 which are almost the same as the xmlpp library. I especially like that I can write a method getFoo that takes a stream reader and pulls from it and returns a Foo object. It's sort of the best between DOM and SAX. I think it may be referred to as StAX by some.
I'm getting a little ramble-y so I'm quitting now

Categories

Resources