xpath parsing multiple values in a single call - java

How do you get xPath value for more than one path in a single call.
for example
<Message version="010" release="006" xmlns="http://www.ncpdp.org/schema/SCRIPT" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Header>
</Header>
<Body>
<CommunicationNumbers>
<Communication>
<Number>5551234444</Number>
<Qualifier>TE</Qualifier>
</Communication>
<Communication>
<Number>5551235555</Number>
<Qualifier>FX</Qualifier>
</Communication>
</CommunicationNumbers>
<Identification>
<FileID>616</FileID>
<DEANumber>AB123456</DEANumber>
<SocialSecurity>123456789</SocialSecurity>
</Identification>
<Specialty>A</Specialty>
<ClinicName>Therapy Department</ClinicName>
<Name>
<LastName>Xavior</LastName>
<FirstName>Charles</FirstName>
<MiddleName>C</MiddleName>
<Suffix>MD</Suffix>
</Name>
<Address>
<AddressLine1>888 ABC Drive</AddressLine1>
<AddressLine2>Suite 200</AddressLine2>
<City>Miami</City>
<State>FL</State>
<ZipCode>12345</ZipCode>
</Address>
</Body>
and I need values for :
:Communication/Number
:Identification/FileID
:Specialty
in a single call.
For a single value I am using
public static String getExpValue(final String xmlString, final String expression, final ServiceNamespaceContext nameSpace) throws XPathExpressionException {
StringReader strReader = new StringReader(xmlString);
InputSource inputStr = new InputSource(strReader);
String result = null;
try {
final XPath xpath = XPathFactory.newInstance().newXPath();
xpath.setNamespaceContext(nameSpace);
final XPathExpression expr = xpath.compile(expression);
result = (String) expr.evaluate(inputStr, XPathConstants.STRING);
} finally {
strReader = null;
inputStr = null;
}
return result;
}
My desired output is a single concatenated String 5551234444616A

You could try using something like...
XPathExpression expr = xpath.compile("//Communication/Number | //Identification/FileID");
Which should combine the results of each query. In my (simply) test, I got 3 matches (2 for Communication/Number and 1 for Identification/FileID)
Updated
The intended result was to return a NodeList, for example...
NodeList nl = (NodeList)expr.evaluate(inputStr, XPathConstants.NODELIST);
for (int index = 0; index < nl.getLength(); index++) {
Node node = nl.item(index);
String value = node.getTextContent();
System.out.println(value);
}

Since Java 7 the NodeList is replaced by NodeSet:
NodeList nl = (NodeList)expr.evaluate(inputStr, XPathConstants.NODESET);
for (int index = 0; index < nl.getLength(); index++) {
Node node = nl.item(index);
String value = node.getTextContent();
System.out.println(value);
}

Related

Get node text with HTML task inside

I try to examine with Java XPath an html string like this:
<app>
<elem class="A">value1</elem>
<elem class="B">value2a<br />value2b</elem>
<elem class="C">value3</elem>
</app>
Actually for obtain the elem's value i use this code
public String getValue(String xml, String classValue){
XPath xpath = XPathFactory.newInstance().newXPath();
InputSource source = new InputSource(new StringReader(xml));
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
document = db.parse(source);
String xpathRequest = "//*[#class='"+classValue+"']/text()";
String value = xpath.evaluate(xpathRequest , document);
return value;
}
For classes A and C works fine, but when i ask the content of task with class B obtain only value2a
How i can get the complete string of node?
Simply run
String xpathRequest = "//*[#class='"+class+"']";
String value = this.xpath.evaluate(xpathRequest , document);
This will select the <elem> node and when converted to a String build the concatenation of all text content, e.g. Value2a Value2b
To get a list of all text contents below a Elem you need to select them as NodeSet:
String xpathRequest = "//*[#class='"+class+"']/text()";
NodeList textNodes = (NodeList)xpath.evaluate(xpathRequest , document, XPathConstants.NODESET);
ArrayList<String> texts = new ArrayList<>();
for (int i=0; i<textNodes.getLength(); i++)
texts.add(textNodes.item(i).getTextContent());
It is because xpath will return 2 value at this moment. Try below :-
List<WebElement> allprice = driver.findElements(By.xpath("//*[#class='B']/text()"));
for(WebElement a:WebElement allprice){
System.out.println(a.gettext());
}

Getting a node's children depending on another children's text

I want to get the english or hungarian elements' text depending on the title. So far, I came up with this. Can you help me with a cleaner or more professional solution for this using xpath?
The XML:
<Textbook>
<TEXT>
<Title>SAMPLE TITLE 1</Title>
<English>Sample english text</English>
<Hungarian>Sample hungarian text</Hungarian>
</TEXT>
<TEXT>
<Title>SAMPLE TITLE 2</Title>
<English>Sample english text 2</English>
<Hungarian>Sample hungarian text 2</Hungarian>
</TEXT>
</Textbook>
The code:
public String getResults (String elementName, String language) throws XPathExpressionException {
xpathFactory = XPathFactory.newInstance();
xpath = xpathFactory.newXPath();
XPathExpression expr = xpath.compile("/Textbook/TEXT/Title");
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
if (nodes.item(i).getTextContent().equals(elementName)) {
XPathExpression expr2 = xpath.compile("/Textbook/TEXT/" + language);
NodeList nodes2 = (NodeList) expr2.evaluate(doc, XPathConstants.NODESET);
return nodes2.item(i).getTextContent();
}
}
return null;
}
You can filter <TEXT> by it's chld <Title> content. For example, this XPath will get <TEXT> having child <Title> with content equals "SAMPLE TITLE 1" :
//TEXT[Title='SAMPLE TITLE 1']
So your requirement can actually be fulfilled using single XPath like so :
.....
String path = "/Textbook/TEXT[Title='" + elementName + "']/" + language
XPathExpression expr = xpath.compile(path);
NodeList nodes = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
return nodes.item(i).getTextContent();
}
.....

Reading a complex XML Java

Thanks for considering this question.
I'm reading a complex XML file, which as you can see in the code has 44 main "nodes". Each node has further nested elements and so on.
I have managed to read the info from the first node but it seems that after the first iteration, returns only null. What could I be missing?
for (int i=0; i<nodeList.getLength(); i++){
log(String.valueOf(i));
Element flightInfo = (Element)nodeList.item(i);
NodeList flights = flightInfo.getElementsByTagName("flight");
Element flight = (Element)flights.item(0);
String flightId = flight.getAttribute("id");
String airlineCode = flight.getAttribute("airlineCode");
String operationType = flight.getAttribute("operationType");
String flightRoute= flight.getAttribute("flightType");
String scheduledTime = flight.getAttribute("scheduledTime");
NodeList routingList = flight.getElementsByTagName("routingList");
Element iatas = (Element)routingList.item(0);
NodeList _iata = (iatas.getElementsByTagName("IATA"));
String iata = _iata.item(i).getFirstChild().getNodeValue();
NodeList times = flight.getElementsByTagName("times");
Element realTimes = (Element)times.item(0);
NodeList _realTime = (realTimes.getElementsByTagName("realTime"));
String realTime = _realTime.item(0).getFirstChild().getNodeValue();
NodeList means = flight.getElementsByTagName("means");
Element gates = (Element)means.item(0);
NodeList _gate = gates.getElementsByTagName("gate");
Element gate = (Element)_gate.item(0);
String gateId = gate.getAttribute("id");
Element bagClaimList = (Element)means.item(0);
NodeList bagClaims = bagClaimList.getElementsByTagName("bagClaim");
Element bagClaim = (Element)bagClaims.item(0);
String bagId = bagClaim.getAttribute("id");
Element standList = (Element)means.item(0);
NodeList stands = standList.getElementsByTagName("stand");
Element _stand = (Element)stands.item(i);
String standId = _stand.getAttribute("id");
NodeList remarks = flight.getElementsByTagName("flight");
Element remarkCodes = (Element)remarks.item(0);
NodeList _remarkCode = (remarkCodes.getElementsByTagName("remarkCode"));
String remarkCode = _remarkCode.item(0).getFirstChild().getNodeValue();
flightList.add(new Flight(flightId, airlineCode, operationType,iata, scheduledTime, iata, realTime, gateId, bagId, standId, remarkCode));
log("Added new flightInfo");
}
The XML I'm reading is the following:
<flightData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="file://c:/SITA/IKUSI FIDS/FIDS.XSD">
<flightInfo>
<flight id="AM2613" airlineCode="AM" flightNumber="2613" operationType="D" flightType="D" scheduledTime="2013-07-18T07:00:00">
<routingList>
<IATA>MTY</IATA>
</routingList>
<times>
<realTime>2013-07-18T07:00:00</realTime>
</times>
<means>
<gateList>
<gate id="N/14"/>
</gateList>
<bagClaimList>
<bagClaim id="2"/>
</bagClaimList>
<standList>
<stand id="5"/>
</standList>
</means>
<remarks>
<remarkCode>DEP</remarkCode>
</remarks>
</flight>
</flightInfo>
<flightInfo>...</flightInfo>
<flightInfo>...</flightInfo>
<flightInfo>...</flightInfo>
<flightInfo>...</flightInfo>
You'd be better off using JAXB: with the xsd file you will be able to generate java classes representing your model and won't have to write all this data extraction code.

Android :Parse XML Data: Tags with arguments

I want to parse an XML file i exported from a database software, for my android app.
However some of the tags have arguments like so:
<row>
<value column="Index" null="false">1</value>
<value column="Front" null="false">INFO</value>
<value column="Back" null="false">INFO</value>
<value column="Check" null="false">0</value>
</row>
what string value do i specify while trying to find the start tag to parse it?
( for example: to find the row i compare the start tap to "row" and if it returns true i compute the data. What do i do for each value i.e Index,Front,Back and Check separately?)
My java code is as follows
try{
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
factory.setNamespaceAware(true);
XmlPullParser xpp = factory.newPullParser();
InputStream stream = context.getResources().openRawResource(com.Whydea.chemistryhelper.R.raw.appxml);
xpp.setInput(stream, null);
int eventType = xpp.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT){
if(eventType==XmlPullParser.START_TAG){
handleStartTag(xpp.getName()); //handels Start Tag
} else if (eventType==XmlPullParser.END_TAG){
handleEndTag(xpp.getName());
Ctag=null;
} else if (eventType==XmlPullParser.TEXT){
handleText(xpp.getText());
}
eventType=xpp.next();
}
}catch (NotFoundException e){
Log.d("XMLpp",e.getMessage());
}catch (XmlPullParserException e){
Log.d("XMLpp",e.getMessage());
}catch (IOException e){
Log.d("XMLpp",e.getMessage());
}
`
EDIT:
Each "value" start tags has its own attribute(column=...), how do i access those?
For example: to access a row, i have a String constant with the value "row", and check if the start tag corresponds to that, and it works. But when i declare a string constant with value "value column=\"Check\" null=\"false\""( i have to use \ other wise " give errors), it does not find find that start tag. So what should my constant be?
if i understand your question correctly then to get each of the values you need to do following, basically you want to get the value of each attribute inside the xml tag
int attributeCount = xpp.getAttributeCount();
for(int i = 0; i<attributeCount; i++){
String name = xpp.getAttributeName(i);
//Log.d(TAG, "Name: "+name);
if(name != null && name.equalsIgnoreCase("column")){
return Integer.parseInt(xpp.getAttributeValue(i));
}
}
So once you have encountered the row then you look for the start Tag "value" once you have found it, then use the above code to get the individual value of attributes.
As per your comment if you want to get the text value of an XML tag then you will have to use the getText() method. Once you have found the START_TAG value then execute below code:
eventType = xpp.next();
if(eventType == XmlPullParser.TEXT){
String text = xpp.getText();
}
For the xml tag 'INFO' value it will return 'INFO'
try {
final Service S = new Service();
String xmlString = S.ImportAllPollBoothStatus(IMEI,asscd, boothno);
if(xmlString.toLowerCase().trim().equals("false")){
return false;
}
DocumentBuilderFactory docFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlString));
Document doc = docBuilder.parse(is);
NodeList nodes = doc.getElementsByTagName("HT");
for (int i = 0; i < nodes.getLength(); i++) {
Element element = (Element) nodes.item(i);
NodeList blockidnodes = doc.getElementsByTagName("Table");
for (int blockidcount = 0; blockidcount < blockidnodes
.getLength(); blockidcount++) {
NodeList PollpercentId = element
.getElementsByTagName("PollpercentId");
Element line1 = (Element) PollpercentId.item(blockidcount);
NodeList asscd1 = element
.getElementsByTagName("asscd");
Element line2 = (Element) asscd1.item(blockidcount);
NodeList pollgcd = element
.getElementsByTagName("pollgcd");
Element line3 = (Element) pollgcd.item(blockidcount);
NodeList SessionYearIdref = element
.getElementsByTagName("SessionYearIdref");
Element line4 = (Element) SessionYearIdref.item(blockidcount);
NodeList MaleVoters = element
.getElementsByTagName("MaleVoters");
Element line5 = (Element) MaleVoters.item(blockidcount);
NodeList FemaleVoters = element
.getElementsByTagName("FemaleVoters");
Element line6 = (Element) FemaleVoters.item(blockidcount);
NodeList UpdatedDate = element
.getElementsByTagName("UpdatedDate");
Element line7 = (Element) UpdatedDate.item(blockidcount);
NodeList timeslot = element
.getElementsByTagName("timeslot");
Element line8 = (Element) timeslot.item(blockidcount);
this.db.insertVotingStatus(
getCharacterDataFromElement(line1),
getCharacterDataFromElement(line2),
getCharacterDataFromElement(line3),
getCharacterDataFromElement(line4),
getCharacterDataFromElement(line5),
getCharacterDataFromElement(line6),
getCharacterDataFromElement(line7),
getCharacterDataFromElement(line8));
}
}
}
catch (Exception e) {
Log.e("EXCEPTION DURING VIDHANSABHA INSERION",
"======Insert-VIDHANSABHA-DETAILS=====================" + e);
return false;
}
return true;
Did you develop the app which generates the XML file? If so why don't you change it? It would be much easier to parse the XML if it has this format:
<item Index="1" Front="INFO" Back="INFO" Check="0"/>
<item Index="2" Front="INFO" Back="INFO" Check="1"/>

Parsing xml string containing hyperlink

I am using DOM to parse an XML string as in the following example. This works great except in one instance. The document which I am trying to parse looks like this:
<response requestID=\"1234\">
<expectedValue>Alarm</expectedValue>
<recommendations>For steps on how to resolve visit Website and use the search features for \"Alarm\"<recommendations>
<setting>Active</setting>
<response>
The code I used to parse the XML is as follows:
try {
DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlResult));
Document doc = db.parse(is);
NodeList nlResponse = doc.getElementsByTagName("response");
String[] String = new String[3]; //result entries
for (int i = 0; i < nlResponse.getLength(); i++) {
Element e = (Element) nlResponse.item(i);
int c1 = 0; //count for string array
NodeList ev = e.getElementsByTagName("expectedValue");
Element line = (Element) ev.item(0);
String[c1] = (getCharacterDataFromElement(line));
c1++;
NodeList rec = e.getElementsByTagName("recommendations");
line = (Element) rec.item(0);
String[c1] = (getCharacterDataFromElement(line));
c1++;
NodeList set = e.getElementsByTagName("settings");
line = (Element) set.item(0);
String[c1] = (getCharacterDataFromElement(line));
c1++;
I am able to parse the code and put the result into a string array (as opposed to the System.out.println()). With the current code, my string array looks as follows:
String[0] = "Alarm"
String[1] = "For steps on how to resolve visit"
String[2] = "Active"
I would like some way of being able to read the rest of the information within "Recommendations" in order to ultimately display the hyperlink (along with other output) in a TextView. How can I do this?
I apologize for my previous answer in assuming your xml was ill-formed.
I think what is happening is that your call to the getCharacterDataFromElement is only looking at the first child node for text, when it will need to look at all the child nodes and getting the href attribute as well as the text for the 2nd child node when looking at the recommendations node.
e.g. after getting the Element for recommendation
String srec = "";
NodeList nl = line.getChildNodes();
srec += nl.item(0).getTextContent();
Node n = nl.item(1);
NamedNodeMap nm = n.getAttributes();
srec += "" + n.getTextContent() + "";
srec += nl.item(2).getTextContent();
String[c1] = srec;

Categories