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.
Related
public void loadSettings() {
try {
File inputFile = new File("data.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(inputFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("Setting");
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nList.item(temp);
NodeList VariableName = eElement.getElementsByTagName("VariableName");
NodeList VariableValue = eElement.getElementsByTagName("VariableValue");
System.out.println(VariableName.item(0).getTextContent());
if (VariableName.item(0).hasChildNodes()) {
}
// txtBookmarkUrl.setText(bookMarkUrl);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
I want to make a function that gets second part of the xml in settings elements. I want the function to return a result so that i can assign it to textfield default value when the swing GUI starts. The function should take let's say 'isDecaptcher' variable name and return '0' VariableValue.
<Bookmark>
<Setting>
<VariableName>isDeathbycaptcha</VariableName>
<VariableValue>0</VariableValue>
</Setting>
<Setting>
<VariableName>isDecaptcher</VariableName>
<VariableValue>0</VariableValue>
</Setting>
<Setting>
<VariableName>isExpertdecoders</VariableName>
<VariableValue>0</VariableValue>
</Setting>
<Setting>
<VariableName>ManualCaptcha</VariableName>
<VariableValue>1</VariableValue>
</Setting>
</Bookmark>
public void loadSettings(String variableName) {
try {
File inputFile = new File("data.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(inputFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("Setting");
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nList.item(temp);
NodeList VariableName = eElement.getElementsByTagName("VariableName");
NodeList VariableValue = eElement.getElementsByTagName("VariableValue");
if (VariableName.item(0).getTextContent().equalsIgnoreCase(variableName)) {
String txtBookmarkUrlValue = VariableValue.item(0).getLastChild().getTextContent();
System.out.println(txtBookmarkUrlValue);
txtBookmarkUrl.setText(txtBookmarkUrlValue);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
This works, But if you have more robust answers you can share.
First of all create an Object wich will represent your settings. The case is to reuse it's values in whole app. I assume that you will use it only once at the beginning and settings will not change. Singleton pattern would fit there.
final class Settings{
private static volatile Settings instance = null;
private boolean _isDeathByCaptcha;
private boolean _manualCaptcha;
...
//getters & setters
public boolean isDeathByCaptcha(){
return _isDeathByCaptcha;
}
public void setIsDeathByCaptcha(boolean isDeathByCaptcha){
this._isDeathByCaptcha = isDeathByCaptcha;
}
private Settings(){}
public static Settings getInstance(){
if(instance == null){
synchronized (Settings.class) {
if (instance == null) {
instance = new Settings();
}
}
}
return instance;
}
}
After that you can call Settings.getInstance().isDeathByCaptcha(); to get your value. Of course you need to set it earlier with setter.
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);
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);
this is my XML file :
<sitemesh>
<mapping path="/editor/tempPage/**" exclude="true"/>
<mapping decorator="/WEB-INF/views/decorators/detailstheme.jsp"
path="/*" exclude="false" />
</sitemesh>
I want list of mapping node with their attribute values.
this should be done using Xpath.
my xpath expression is :
expr = xpath.compile("/sitemesh/mapping");
but i am getting null in nodelist.
this is my code:
Map<String,String> map=new HashMap<String, String>();
// reading xml file
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder;
Document doc = null;
XPathExpression expr = null;
try {
builder = factory.newDocumentBuilder();
// creating input stream
doc = builder.parse(file);
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
expr = xpath.compile("//mapping");
} catch (Exception e) {
LOG.error("some exception message", e);
}
//------------------------------------------------------------------------
NodeList attributeElements = null;
try {
attributeElements =(NodeList)expr.evaluate(doc, XPathConstants.NODE);
} catch (XPathExpressionException e) {
LOG.error("some exception message", e);
}
System.out.println("lenght:"+attributeElements.getLength());
for (int i = 0; i < attributeElements.getLength(); i++) {
Node node=attributeElements.item(i);
System.out.println("node:"+node.getNodeValue());
NamedNodeMap attrs = node.getAttributes();
for(i = 0 ; i<attrs.getLength() ; i++) {
Attr attribute = (Attr)attrs.item(i);
System.out.println("Node Attributes : " + attribute.getName()+" = "+attribute.getValue());
}
}
//-------------------------------------------------------------------------
// writing xml file
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer;
try {
transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(file);// creating output
// stream
transformer.transform(source, result);
} catch (Exception e) {
LOG.error("some exception message", e);
}
return map;
i am getting null for attributeElements
i want to show values of path,decorator and exclude on JSP page.But i am unable to get list of node through xpath expression.
I want solution for reading mapping node element in Xpath.
[edit] /sitemesh/mapping also works .
The issue here is that you evaluating the express for XPathConstants.NODE while the nodeList maps to XPathConstants.NODESET. please refer below link.
http://docs.oracle.com/javase/1.5.0/docs/api/javax/xml/xpath/XPathConstants.html#NODESET
Added sample code for illustration purpose only:
public void testXpathExpr(){
String testXML = "<sitemesh><mapping path=\"/editor/tempPage/**\" exclude=\"true\"/><mapping decorator=\"/WEB-INF/views/decorators/detailstheme.jsp\" path=\"/*\" exclude=\"false\" /></sitemesh>";
NodeList nodeList = getNodeList(testXML);
}
private NodeList getNodeList(String xml) throws SAXException, IOException, ParserConfigurationException, XPathExpressionException {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = docFactory.newDocumentBuilder();
document = builder.parse(new ByteArrayInputStream( xml.getBytes() ) );
XPathExpression exprPath = xpath.compile(xpathExpr);
NodeList nodeList = (NodeList) exprPath.evaluate(document, XPathConstants.NODESET);;
return nodeList;
}
Hope this helps!
Your xpath works perfectly for me. Below is the sample code:
public class Parser {
public static void main(String[] args) throws Exception, Exception {
final DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
final DocumentBuilder builder = factory.newDocumentBuilder();
final Document doc = builder.parse("src/sitemesh.xml");
final XPathFactory xPathfactory = XPathFactory.newInstance();
final XPath xpath = xPathfactory.newXPath();
final XPathExpression expr = xpath.compile("/sitemesh/mapping");
Object node = expr.evaluate(doc, XPathConstants.NODE);
System.out.println(node);
}
}
sitemesh.xml contains your sample input.
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;
}
});