I want to try parse xml with XPath in Android Application.
My XML file looks like this.
<expenses>
<entry type="fixed">
<amount>200</amount>
<recurring>true</recurring>
<category>Home/Rent</category>
<payee>Ahmet Necati</payee>
<account>1</account>
<startDate>2013-01-01</startDate>
<endDate>2013-01-01</endDate>
</entry>
<entry type="variable">
<amount>150</amount>
<category>Departmental</category>
<payee>Ahmet Necati</payee>
<recurring>true</recurring>
<startDate>2013-01-01</startDate>
<endDate>2013-01-01</endDate>
<account>1</account>
</entry>
</expenses>
and I want to try parse xml with xPath like that
String expression = "/expenses/entry[xs:date(endDate) < xs:date('2013-10-10')]";
NodeList widgetNode = (NodeList) xpath.evaluate(expression, document,
XPathConstants.NODESET);
But I couldnt deal with it. It returns 0 node.
Edit: I want to get all nodes "endDate" less than spesific date for example: I want to get nodes which end Date less than "2013-10-10"
The "XML schema constructor functions" are part of XPath 2.0, but Android only supports XPath 1.0: http://developer.android.com/reference/javax/xml/xpath/package-summary.html
One solution is to register your own function to do the conversion (see XPathFunctionResolver). Another is to look into libraries that support XPath 2.0.
Related
When I am printing my API response, which gives me below xml as Response:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<BugInfo xmlns="ctessng" xmlns:ns2="http://www.w3.org/1999/xlink">
<Bug id="CSCvz53137">
<Field name="Assigned Date">09/01/2021 21:12:25</Field>
<Field name="Archived">N</Field>
<Field name="Assigner">James Vilson</Field>
<Field name="Status">V</Field>
<Field name="Submitter">Spark Mery</Field>
<Field name="Reason">Technically Inaccurate</Field>
<Field name="Regression">Y</Field>
<Field name="Resolved Date">09/02/2021 02:12:37</Field>
<Field name="Version">001.010</Field>
</Bug>
</BugInfo>
I want to fetch only specific values form this xml, like Assigned Date, Assigner, Submitter & Resolved-on
Assigned Date --> 09/01/2021 21:12:25
Assigner --> James Vilson
Submitter --> Spark Mery
Resolved Date --> 09/02/2021 02:12:37
What is the best/simplest way to read in values from this xml?
Regex
The most versatile would be plain text-filtering (match/find, extract) using a regular expression:
<Field name=\"(Assigned Date|Assigner|Submitter|Resolved Date)\">(.*)<
Iterating with find() then group(1) and group(2) can give you the desired strings.
See this regex demo
XPath
The pure XML-parsing way would be to use any XML parser, like DocumentBuilderFactory and SAXParser which can be used to read the XML into a document, then find the desired XML-nodes (Field elements) via XPath expression:
/BugInfo/Bug/Field[#name="Assigner"]|//Field[#name="Assigned Date"]|//Field[#name="Submitter"]|//Field[#name="Resolved Date"]
Iterating over the found nodes we can extract the child as text value.
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList nodes = (NodeList) xPath.compile(xPathExpression).evaluate(xmlDocument, XPathConstants.NODESET);
See:
Filtering XML Document using XPATH in java
XPath OR operator for different nodes
XML mapping
The object-oriented way would use an XML mapper like Jackson to deserialize (unmarshall) the XML to an object.
Similar to the OkHTTP Recipe: Parse a JSON Response With Moshi (.kt, .java)
Then you would need a class where you can map the XML nodes to.
class Bug {
String submitter;
String assigner;
Date assignedOn;
Date resolvedOn
}
The mapping can be a bit tricky here, because from XML-model point-of-view a Bug node contains a collection of children Fields. But the target type, is semantically not a field-list, but a Bug-object with different typed properties.
This is probably the cleanest because it will be easy to parse: Bug bug = new XmlMapper().readValue(xmlString, Bug.class).
My XML file
<classifications>
<classification sequence="1">
<classification-scheme office="" scheme="CS" />
<section>G</section>
<class>01</class>
<subclass>R</subclass>
<main-group>33</main-group>
<subgroup>365</subgroup>
<classification-value>I</classification-value>
</classification>
<classification sequence="2">
<classification-scheme office="" scheme="CS" />
<section>G</section>
<class>01</class>
<subclass>R</subclass>
<main-group>33</main-group>
<subgroup>3415</subgroup>
<classification-value>A</classification-value>
</classification>
<classification sequence="1">
<classification-scheme office="US" scheme="UC" />
<classification-symbol>324/300</classification-symbol>
</classification>
<classification sequence="2">
<classification-scheme office="US" scheme="UC" />
<classification-symbol>324/307</classification-symbol>
</classification>
</classifications>
I want to parse the value with following condition
required all the classification-symbol element value along with condition office="US"
I tried with below XPath,
NodeList usClassification = (NodeList)xPath.compile("//classifications//classification//classification-scheme[#office=\"US\"]//classification-symbol//text()").evaluate(xmlDocument, XPathConstants.NODESET);
but I'm getting an empty result set,
System.out.println(usClassification.getLength()); //its becomes zero
This XPath (written on two lines to ease readability),
/classifications/classification[classification-scheme/#office='US']
/classification-symbol/text()
will select the classification-symbol text of the classification elements with classification-scheme #office attribute value equal to US:
324/300
324/307
as requested.
classification-symbol is not a child of classification-scheme - they are siblings. Use following-sibling axis to get from "scheme" to "symbol" instead:
//classifications/classification/classification-scheme[#office=\"US\"]/following-sibling::classification-symbol/text()
I have an xml file containing a lists of nodes with a "date" attribute, storing a date:
<root>
<entry date="2011-12-04" />
<entry date="2011-11-29" />
</root>
Is it possible using a xPath query to retrive all the nodes that have the month of the "date" attribute set to november?
I read on the web (for example here) that this kind of functions exists in the xPath language, but I am not able to figure how to use them.
I should using this in a java application.
The following XPath works for me:
//entry[month-from-date(#date)=11]
(Replace entry with * to select all the nodes with a November date attribute, regardless of the node name.)
I haven't used the date functions, but you could use substring to extract the month and test that value, for example:
'//entry[substring(#date,6,2)="11"]'
returns just
<entry date="2011-11-29" />
i have response structure that i want to parse in Java. Can anyone help me with this?
<message_response xmlns="">
<action name="GETCIL">
<param name="bookingNote" value="" require="" read-only=""><![CDATA[bookingNote]]></param>
<param name="CarrierLinkType" value="" require="" read-only=""><![CDATA[True]]></param>
<param name="Carrier" value="" require="" read-only=""><![CDATA[SK185]]></param>
<param_list name="ViaAddressList" id="GETCIL">
<value>
<param_list name="ViaAddressId" id="ViaAddressList">
<value><![CDATA[877765050_5511]]></value>
</param_list>
<param_list name="AddressDate" id="ViaAddressList">
<value><![CDATA[10/12/2010]]></value>
</param_list>
<param_list name="AddressTime" id="ViaAddressList">
<value><![CDATA[12:12]]></value>
</param_list>
</value>
</param_list>
</action>
</message_response>
The easiest way to extract specific values from an XML document (as opposed to parsing the complete document with SAX) is to use XPath as follows:
//1. load the document into memory.
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
//2. Create an XPath.
XPath xpath = XPathFactory.newInstance().newXPath();
//3. Evaluate the xpath expression.
String actionName = xpath.evaluate("/message_response/action/#name", documentBuilder.parse(xmlFile));
There's not much more to it other than the XPath.evaluate method is overloaded in order to allow nodes and node lists to be returned (see javax.xml.xpath.XPathConstants for the types).
Then you just need to read-up on the xpath syntax (http://www.w3schools.com/xpath/xpath_syntax.asp).
Why the CDATA sections around the data?
You can use SAX or DOM to parse XML.
There are also libraries wrapping SAX and DOM parsers that make your life easier for common tasks. Two that come to mind for Java are JDOM and DOM4J. Google for them - there are tutorials and examples available that will show you what you need to know.
I have the following xml:
<config xmlns="http://www.someurl.com">
<product>
<brand>
<content />
</brand>
</product>
</config>
I'm reading it nicely into JDOM.
However, when I try to use Jaxen to grab the contents, I can't seem to get anything.
Here's an example of what doesn't seem to work:
XPath xpath = new JDOMXPath("config");
SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
namespaceContext.addNamespace("", "http://www.someurl.com");
xpath.setNamespaceContext(namespaceContext);
assert xpath.selectNodes(document).size() > 0 : "should find more than 0";
This assertion always fails.
What am I doing wrong?
You have to assign a prefix. Make that call addNamespace("hopfrog", "http://...");
Then make the XPath ("hopfrog:config");
Keep in mind that the prefixes in XML aren't part of the real data model. The real data model assigns a URL, possibly blank, to each element and attribute. You can use any prefix you want in XPath so long as it's bound to the right URL. Since the URL you want it blank, you bind a prefix to 'blank'.