How can I parse this list in Java? I have List<Image> which returns from server, but I can't get a single item.
<images>
<image>
uploads/posts/2008-10/1225141003_1-21.jpg
</image>
<image>
uploads/posts/2008-10/1225141003_1-22.jpg
</image>
</images>
#Root(name = "Images") public class Images {
#ElementList(required=false, inline = true)
private List<Image> imageList;
public List<Image> getImageList() {
return imageList;
}
}
#Root(name = "image") public class Image {
//Some code.......
}
I solved this problem in this way:
#Root(name = "images")
public class Images {
#ElementList(entry = "image", required=false, inline = true)
private List<String> imageList;
public List<String> getImageList() {
return imageList;
}
}
Try this:
String inputStreamToString(InputStream is) {
String line = "";
String total = "";
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
try {
while ((line = rd.readLine()) != null) {
total +=line;
}
} catch (IOException e) {
e.printStackTrace();
}
return total;
}
EDIT
If you are able to get that xml:
String responseXML = inputStreamToString(yourXMLResponseFromServer.getEntity().getContent());
To interpret XML files I have always used the org.w3c.dom.Document Interface which offers a Javascript like document modification. Check out the Documentation on the oracle website!
Use DOM and Xpath
1 Parse your String
String xml="<my_xml/>";
DocumentBuilderFactory builderFactory =DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(xml)));
2 use an xpath
XPath xPath = XPathFactory.newInstance().newXPath();
String expression="/images/image";
XPathExpression expr = xpath.compile(expression) ;
NodeList nodes = (NodeList) expr.evaluate(document, XPathConstants.NODESET);
3 iterate
for (int k = 0; k < nodes.getLength(); k++)
{
Node nodeSegment = nodes.item(k);
if (nodeSegment.getNodeType() == Node.ELEMENT_NODE)
{
Element eElement = (Element) nodeSegment;
System.out.println("TEXT CONTENT="+eElement.getTextContent());
ALTERNATIVE:
If you know you have 1 or 2 image (s):
expression="/images/image[1]"; // first one
String value = xPath.evaluate(expression, document);
System.out.println("EVALUATE:"+value);
Related
It may be a basic question, but I could not manage to find a correct answer. Maybe it is an exceptional usage of SimpleXML.
In SimpleXML (java) I want to read some attributes of an object from XML and then save the Object again to another XML without writing those attributes.
I want to read "Question" object from this XML definition:
<question>
<questionID>0</questionID>
<category>tarih</category>
<difficultyLevel>80</difficultyLevel>
<text>Tarihte gelmiş geçmiş en büyük sınırlara ulaşan imparatorluk, aşağıdakilerden hangisidir?</text>
<alternatives length="4">
<string>Britanya</string>
<string>Roma</string>
<string>Moğol</string>
<string>Osmanlı</string>
</alternatives>
<answerID>0</answerID>
And Serialize it back as follows by eliminating the "alternatives" fields:
<question>
<questionID>0</questionID>
<category>tarih</category>
<difficultyLevel>80</difficultyLevel>
<text>Tarihte gelmiş geçmiş en büyük sınırlara ulaşan imparatorluk, aşağıdakilerden hangisidir?</text>
<answerID>0</answerID>
</question>
Is this possible?
Edit: The java class definition of "Question":
public class Question {
public final static int N_POSSIBLE_ANSWERS=4;
public final static String[] ALTERNATIVE_CAPTIONS = {"A","B","C","D"};
// Attributes
#Element
public int questionID;
#Element
public String category;
#Element
public int difficultyLevel;
#Element
public String text;
#ElementArray
private String[] alternatives;
#Element(required=false)
private int answerID = -1;
// State variables
private int nAddedAlternatives=0;
public String[] getAlternatives() {
return alternatives;
}
public void addAlternative(String alternative){
if(alternatives == null){
alternatives = new String[N_POSSIBLE_ANSWERS];
}
alternatives[nAddedAlternatives] = alternative;
nAddedAlternatives++;
}
public void clearAlternatives(){
nAddedAlternatives = 0;
alternatives = null;
}
public String getAlternative(int i){
//String result = ALTERNATIVE_CAPTIONS[i];
//result += ": ";
String result = alternatives[i];
return result;
}
public int getAnswer(){
return answerID;
}
public void setAnswer(int answer){
answerID = answer;
}
}
The ElementArray defined as "alternatives" is the interest point of this question.
Best regards,
fercis
Please use the below method to convert that
public static void convert(InputStream inputStream,OutputStream outputStream,List<String> result) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(inputStream);
if(inputStream != null)
inputStream.close();
NodeList childNodes = document.getChildNodes().item(0).getChildNodes();
Document writeDoc = builder.newDocument();
Element rootElement = writeDoc.createElement(document.getChildNodes().item(0).getNodeName());
for (int i = 0; i < childNodes.getLength(); i++) {
Node item = childNodes.item(i);
if(result.contains(item.getNodeName())) {
System.out.println("Skipped ...");
continue;
}
Node node = item.cloneNode(true);
writeDoc.adoptNode(node);
rootElement.appendChild(node);
}
writeDoc.appendChild(rootElement);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(writeDoc);
transformer.transform(source, new StreamResult(outputStream));
} catch (Exception e) {
e.printStackTrace();
}
}
This is the method which take the input as a InputStream, will return result in OutPutStream, will accept List of String that need to be filtered.
My xml String is
Got message from Queue ==> <?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003
/05/soap-envelope"><soapenv:Body><ns1:PostPublicationResponse xmlns:ns1="http://www.openoandm.org/xml/ISBM/"><ns1:Messag
eID>urn:uuid:7d361fb0-bc54-48bd-bbd1-6e34960ef3f8</ns1:MessageID><ns1:MessageContent><MessageContent xmlns="http://www.o
penoandm.org/xml/ISBM/"><hi>k786</hi></MessageContent></ns1:MessageContent></ns1:PostPublicationResponse></soapenv:Body>
</soapenv:Envelope>
Now i have writtent a function that is trying to get Content of element MessageContent i.e <hi>k786</hi> but i am getting null value always.
My function to parse above xml is:
private String parseQueueMessage(String message)
throws ParserConfigurationException, SAXException, IOException,
XPathExpressionException {
String resultMsg = "";
DocumentBuilderFactory domFactory = DocumentBuilderFactory
.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new java.io.StringReader(
message)));
XPath xpath = XPathFactory.newInstance().newXPath();
// XPath Query for showing all nodes value
xpath.setNamespaceContext(new NamespaceContext() {
#SuppressWarnings("rawtypes")
#Override
public Iterator getPrefixes(String arg0) {
return null;
}
#Override
public String getPrefix(String arg0) {
return null;
}
#Override
public String getNamespaceURI(String arg0) {
if("xmlns:ns1".equals(arg0)) {
return "http://www.openoandm.org/xml/ISBM/";
}
return null;
}
});
XPathExpression expr = xpath.compile("//xmlns:ns1:MessageContent");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println("The message obtained after parsing : "
+ nodes.item(i).getNodeValue());
resultMsg = nodes.item(i).getNodeValue();
}
return resultMsg;
}
What i have done wrong in here?
Thanks in advance
You need to define the name space URI first before selecting from XPATH. For example, first define the namespace URI as follows on the root;
element.setAttribute("xmlns:ns1", "http://www.openoandm.org/xml/ISBM/");
xpath.compile("//ns1:MessageContent");
//Try something like ...
XmlDocument doc = new XmlDocument();
doc.LoadXml("urn:uuid:7d361fb0-bc54-48bd-bbd1-6e34960ef3f8k786
");
XmlElement elem = (XmlElement) doc.DocumentElement.FirstChild;
Console.Write("{0}:{1} = {2}", elem.Prefix, elem.LocalName, elem.InnerText);
Console.WriteLine("\t namespaceURI=" + elem.NamespaceURI);
I use Simple XML (simple-xml-2.6.2.jar) to parse xml file like:
<?xml version="1.0" encoding="UTF-8" ?>
<orderList>
<order id="1">
<name>NAME1</name>
</order>
<order id="2">
<name>NAME2</name>
</order>
</orderList>
The root Element contains subElements.
I wanna it be ArrayList, How to do it?
Here's a possible solution, hope it helps you:
Annotations of Order class:
#Root(name="order")
public class Order
{
#Attribute(name="id", required=true)
private int id;
#Element(name="name", required=true)
private String name;
public Order(int id, String name)
{
this.id = id;
this.name = name;
}
public Order() { }
// Getter / Setter
}
Example class, containing the list:
#Root(name="elementList")
public class Example
{
#ElementList(required=true, inline=true)
private List<Order> list = new ArrayList<>();
// ...
}
And here's some code for reading your code:
Serializer ser = new Persister();
Example example = ser.read(Example.class, file); // file = your xml file
// 'list' now contains all your Orders
List is an interface, ArrayList is one of its implementation, like:
List<Order> l = new ArrayList<Order>()
So if you have a List , you basically have what you want.
If I've interpreted your question correctly, you want a list of orders. I've not tested this for your setup but this works for me for a similar xml structure (assumes you have a custom class called Order):
List<Order> orders = new ArrayList<Order>();
XMLDOMParser parser = new XMLDOMParser();
AssetManager manager = context.getAssets();
InputStream stream;
try {
stream = manager.open("test.xml"); //need full path to your file here - mine is stored in assets folder
Document doc = parser.getDocument(stream);
}catch(IOException ex){
System.out.printf("Error reading xml file %s\n", ex.getMessage());
}
NodeList nodeList = doc.getElementsByTagName("order");
for (int i = 0; i < nodeList.getLength(); i++) {
Element e = (Element) nodeList.item(i); //each order item
Node order=nodeList.item(i);
subList = order.getFirstChild(); //get the name child node
orders.add(order);
}
//XMLDOMParser Class
public class XMLDOMParser {
//Returns the entire XML document
public Document getDocument(InputStream inputStream) {
Document document = null;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = factory.newDocumentBuilder();
InputSource inputSource = new InputSource(inputStream);
document = db.parse(inputSource);
} catch (ParserConfigurationException e) {
Log.e("Error: ", e.getMessage());
return null;
} catch (SAXException e) {
Log.e("Error: ", e.getMessage());
return null;
} catch (IOException e) {
Log.e("Error: ", e.getMessage());
return null;
}
return document;
}
/*
* I take a XML element and the tag name, look for the tag and get
* the text content i.e for <employee><name>Kumar</name></employee>
* XML snippet if the Element points to employee node and tagName
* is name I will return Kumar. Calls the private method
* getTextNodeValue(node) which returns the text value, say in our
* example Kumar. */
public String getValue(Element item, String name) {
NodeList nodes = item.getElementsByTagName(name);
return this.getTextNodeValue(nodes.item(0));
}
private final String getTextNodeValue(Node node) {
Node child;
if (node != null) {
if (node.hasChildNodes()) {
child = node.getFirstChild();
while(child != null) {
if (child.getNodeType() == Node.TEXT_NODE) {
return child.getNodeValue();
}
child = child.getNextSibling();
}
}
}
return "";
}
}
I'm getting some attributes from a complex XML file:
<rsp>
<csl d='10775.916760613756' id='2003' nam='AUTOS TEZIUTLÁN, S.A. DE C.V.'
adr='KM. 1 CARR. TEZIUTLÁN-TLAPACOYAN' tel='231312-12-05'
lat='19.826765' lon='-97.347906' />
<csl d='10789.680721293766' id='2019' nam='AUTOMOVILÍSTICA DE TEHUACAN, S.A. DE C.V.'
adr='BLVD. ADOLFO LOPEZ MATEOS NO. 3623' tel='238382-44-33'
lat='18.467281' lon='-97.417901' />
<csl d='10848.586325071066' id='2013' nam='AUTOMOTRIZ DE LA SIERRA, S.A. DE C.V.'
adr='AUSENCIO T. JIMÉNEZ No. 1' tel='776762-05-42'
lat='20.174386' lon='-98.06125' />
<csl d='10866.815936520663' id='2028' nam='MOTORES ALEMANES RIVERA S.A. DE C.V.'
adr='CALZADA IGNACIO ZARAGOZA NO. 180' tel='222286-02-02'
lat='19.064258' lon='-98.179042' />
<csl d='10867.374198658401' id='2012' nam='ARMENTA AUTOMOTRIZ, S.A. DE C.V.'
adr='24 NORTE No. 214' tel='222235-87-68'
lat='19.038912' lon='-98.183101' />
</rsp>
But my XQUERY only gives me the first attribute and only that using this class:
public class XMLParser {
private String[] resultTable;
public XMLParser(){}
public String[] stringToXML(String xmlString) {
try{
DocumentBuilderFactory dBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dBuilderFactory.newDocumentBuilder();
InputSource iSource = new InputSource();
iSource.setCharacterStream(new StringReader(xmlString));
Document doc = dBuilder.parse(iSource);
NodeList nList = doc.getElementsByTagName("tpr");
resultTable = new String [nList.getLength()];
for (int i=0; i<nList.getLength(); i++){
Element e = (Element)nList.item(i);
NodeList pCode = e.getElementsByTagName("tpr");
Element line = (Element)pCode.item(0);
resultTable[i] = getCharacterDataFromElement(line);
}
}
catch(Exception e) {
e.printStackTrace();
}
return resultTable;
}
public static String getCharacterDataFromElement(Element e) {
Node child = e.getFirstChild();
if (child instanceof CharacterData) {
CharacterData cData = (CharacterData) child;
return cData.getData();
}
return "null";
}
public static String getParamByXPath(String xmlString, String expression) {
String ret = "";
XPath xpath = XPathFactory.newInstance().newXPath();
try{
DocumentBuilderFactory dBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dBuilderFactory.newDocumentBuilder();
InputSource iSource = new InputSource();
iSource.setCharacterStream(new StringReader(xmlString));
Document doc = dBuilder.parse(iSource);
XPathExpression exp = xpath.compile(expression);
Object result = exp.evaluate(doc);
if (result instanceof String) ret = (String)result;
else if (result instanceof Boolean) ret = result.toString();
else if (result instanceof Double) ret = result.toString();
else if (result instanceof NodeList) {
NodeList list = (NodeList) result;
Node node = list.item(0);
Log.d("LIST", Integer.toString(list.getLength()));
ret = node.getTextContent();
}
}catch(Exception e) {
e.printStackTrace();
}
return ret;
}
I'm invoking the method with this line:
String loc1 = XMLParser.getParamByXPath(service, "//#d");
I have been using other Querys, but the result is always the first element... what could I be missing?
The //#d XPath will return a list of all #d attribute nodes in your document.
Your Java code:
else if (result instanceof NodeList) {
NodeList list = (NodeList) result;
Node node = list.item(0); // <-- THIS ONE HERE
Log.d("LIST", Integer.toString(list.getLength()));
ret = node.getTextContent();
}
will then take the first one (list.item(0)) and that's what you're getting.
It looks like your "issue" is with the Java logic, not the XPath.
I have xml like below (Google API), but can't get gphoto:id element value. How to do that ? Notice: When i'm using domFactory.setNamespaceAware(true);, /feed/entry xpath stops working.
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
xmlns:gphoto="http://schemas.google.com/photos/2007"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/">
<entry>
<title type="text">Test</title>
<author>
<name>username</name>
<uri>https://picasaweb.google.com/113422203255202384532</uri>
</author>
<gphoto:id>57060151229174417</gphoto:id>
</entry>
</feed>
Java
NodeList nodes = (NodeList) path(body, "/feed/entry", XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
Node n = nodes.item(i);
XPath xpath = XPathFactory.newInstance().newXPath();
// empty :(
System.out.println(
xpath.evaluate("id[namespace-uri()='http://schemas.google.com/photos/2007']",n)
);
// empty too :(
System.out.println(
xpath.evaluate("gphoto:id",n)
);
// ok
System.out.println(
xpath.evaluate("author",n)
);
l.add(new Album("", "", ""));
}
path method
private Object path(String content, String path, QName returnType) {
try {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(content)));
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile(path);
return expr.evaluate(doc, returnType);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
SOLVED according to #gioele answer path() method is now like below:
private Object path(String content, String path, QName returnType) {
try {
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(content)));
XPath xpath = XPathFactory.newInstance().newXPath();
NamespaceContext nsContext = new NamespaceContext() {
#Override
public Iterator getPrefixes(String namespaceURI) {
return null;
}
#Override
public String getPrefix(String namespaceURI) {
return null;
}
#Override
public String getNamespaceURI(String prefix) {
if ("gphoto".equals(prefix))
return "http://schemas.google.com/photos/2007";
if ("media".equals(prefix))
return "http://search.yahoo.com/mrss/";
if("".equals(prefix))
return "http://www.w3.org/2005/Atom";
throw new IllegalArgumentException(prefix);
}
};
xpath.setNamespaceContext(nsContext);
XPathExpression expr = xpath.compile(path);
return expr.evaluate(doc, returnType);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Before compiling your xpath you need to register a NamespaceContext.
Have a look at the code in https://github.com/gioele/xpathapi-jaxp/blob/master/src/main/java/it/svario/xpathapi/jaxp/NodeNamespaceContext.java.
If you want to avoid all these complications, you can use the XPathAPI library:
Map<String, String> nsMap = new HashMap<String, String>();
nsMap.put(XMLConstants.DEFAULT_NS_PREFIX, "http://www.w3.org/2005/Atom");
nsMap.put("gphoto", "http://schemas.google.com/photos/2007");
List<Node> entries = XPathAPI.selectListOfNodes(doc, "/feed/entry", nsMap);
for (Node entry : entries) {
String id = XPathAPI.selectSingleNodeAsString(entry, "gphoto:id", nsMap);
// or, if you prefer a Node
// Node id = XPathAPI.selectSingleNode(entry, "gphoto:id", nsMap);
}
Disclaimer: I am the creator of XPathAPI-JAXP.
A much easier way to deal with the namespace issue is just to redirect the call from the NamespaceContext to the document lookupNamespaceURI() method. This will return "http://search.yahoo.com/mrss/" when called with "media" etc...
xPath.setNamespaceContext(new NamespaceContext() {
#Override
public String getNamespaceURI(String prefix) {
return doc.lookupNamespaceURI(prefix);
}
#Override
public Iterator<?> getPrefixes(String arg0) {
return null;
}
#Override
public String getPrefix(String arg0) {
return null;
}
});