Get node text with HTML task inside - java

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());
}

Related

XML - Extract One tag Value

I have to extract tag value from an xml Document that contains a single tag like below:
<error>Permission denied</error>
i have tried:
String xmlRecords = "<error>Permission denied</error>"
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(xmlRecords));
Document doc = db.parse(is);
Node nodes = doc.getFirstChild();
String = nodes.getNodeValue();
but it dont works.
How can i do it ?
Use doc.getDocumentElement().getTextContent() to get the string Permission denied.
With DOM it´s util to know the structure of the XML document, and which node level are you looking for.
After get Document, you can use document.getElementsByTagName("root") to look for the root or father tags, and get the childs as a list to look for the item. Something like this:
NodeList listresults = document.getElementsByTagName('father/root element string');
NodeList nl = listresults.item(0).getChildNodes();
// Recorremos los nodos
for (int temp = 0; temp < nl.getLength(); temp++) {
Node node = nl.item(temp);
// Check if it is a node
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
if(element.getNodeName().equals("error")){
// check the element
}
}
}
I hope this helps you.
just try following code.
String value = nodes.getTextContent();
You have to construct the string if you are using the above approach. You will get the string values of the tag name and content using the functions.
Tag name = nodes.getTextContent()
tag value = nodes.getLocalName()
I guess this is what you want
Element element = document.getDocumentElement();
NodeList errorTagList = element.getElementsByTagName("error");
if (errorTagList != null && errorTagList.getLength() > 0) {
NodeList errorTagSubList = errorTagList.item(0).getChildNodes();
if (errorTagSubList != null && errorTagSubList.getLength() > 0) {
String value = errorTagSubList.item(0).getNodeValue();
}
}

How to get xml attribute values using Document builder factory

How to get attribute values by using the following code i am getting ; as output for msg . I want to print MSID,type,CHID,SPOS,type,PPOS values can any one solve this issue .
String xml1="<message MSID='20' type='2635'>"
+"<che CHID='501' SPOS='2'>"
+"<pds type='S'>"
+"<position PPOS='S01'/>"
+"</pds>"
+"</che>"
+"</message>";
InputSource source = new InputSource(new StringReader(xml1));
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.parse(source);
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
String msg = xpath.evaluate("/message/che/CHID", document);
String status = xpath.evaluate("/pds/position/PPOS", document);
System.out.println("msg=" + msg + ";" + "status=" + status);
You need to use # in your XPath for an attribute, and also your path specifier for the second element is wrong:
String msg = xpath.evaluate("/message/che/#CHID", document);
String status = xpath.evaluate("/message/che/pds/position/#PPOS", document);
With those changes, I get an output of:
msg=501;status=S01
You can use Document.getDocumentElement() to get the root element and Element.getElementsByTagName() to get child elements:
Document document = db.parse(source);
Element docEl = document.getDocumentElement(); // This is <message>
String msid = docEl.getAttribute("MSID");
String type = docEl.getAttribute("type");
Element position = (Element) docEl.getElementsByTagName("position").item(0);
String ppos = position.getAttribute("PPOS");
System.out.println(msid); // Prints "20"
System.out.println(type); // Prints "2635"
System.out.println(ppos); // Prints "S01"

Output XML content with unknown node depth using XPath

I have paths of information I want to extract from a XML string:
"/root/A/info1"
"/root/A/B/info2"
"/root/A/B/info3"
"/root/A/info4"
And this is the input:
<root>
<A>
<info1>value1</info1>
<B>
<info2>value2.1</info2>
<info3>value3.1</info3>
</B>
<B>
<info2>value2.2</info2>
<!-- note: element "info3" is missing here! -->
</B>
<B>
<info2>value2.3</info2>
<info3>value3.3</info3>
</B>
<info4>value4</info4>
</A>
</root>
And I want to achieve this:
value1|value2.1|value3.1|value4
value1|value2.2|NULL|value4
value1|value2.3|value3.3|value4
My paths vary and I never know the depth of the XML file. Because "/root/A/B/info2" and "/root/A/B/info3" exist three times, I obviously need to output three lines.
I think recursion is needed here.
My code:
main function:
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(new ByteArrayInputStream(xml.getBytes()));
String[] paths = new String[] {"/root/A/info1", "/root/A/B/info2", "/root/A/B/info3", "/root/A/info4"};
XPath xPath = XPathFactory.newInstance().newXPath();
String[] output = new String[paths.length];
for(int i=0; i<paths.length; i++) {
recursion(paths, doc, xPath, paths[i], i, output);
}
recursive function:
private static void recursion(String[] paths, Object parent, XPath xPath, String path, int position, String[] output) throws Exception {
if(path.contains("/")) { // check if it's the last element, which contains the needed value
List<String> pathNodes = new ArrayList(Arrays.asList(StringUtils.split(path, "/")));
String currentPathNode = pathNodes.get(0);
NodeList nodeList = (NodeList) xPath.compile(currentPathNode).evaluate(parent, XPathConstants.NODESET);
pathNodes.remove(0);
String newPath = StringUtils.join(pathNodes, "/");
for(int i=0; i<nodeList.getLength(); i++) {
Node node = nodeList.item(i);
recursion(paths, node, xPath, newPath, position, output.clone()); // clone?
}
}
else {
output[position] = xPath.compile(path).evaluate(parent);
if((position + 1) == paths.length) { // check if it's the last path, so output the values
System.out.println(StringUtils.join(output, "|"));
}
}
}
If I clone output I get this:
|||value4
If I don't clone output I get that (overwriting previous values):
value1|value2.3|value3.3|value4
Please give me a hint.
Update: Have again a look at the XML input. Text elements which have no value could be missing.
I finally solved it.
I added a context path to my application. It specifies which element is the deepest.
In my example here it would be "/root/A/B".
I update all my paths to be relative to that context path:
"../info1"
"info2"
"info3"
"../info4"
Then I count the nodes from the context path (here 3). That's also the number of lines that will be created. I create a loop to iterate over them and query my updated paths with XPath.

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.

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