Is there a way i can iterate over nodes/elements by their names like this:
<rootnode>
<foo>
<bar>
stuff
</bar>
....
document.getDocumentElement.getElement("foo").getElement("bar").getValue();
I think the XPath should do the trick.
Provided you already have parsed the document as org.w3c.dom.Document:
String expression = "/rootnode/foo/bar";
NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(document, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
System.out.println(nodeList.item(i).getFirstChild().getNodeValue());
}
Related
I have xml as follows,
<students>
<Student><age>23</age><id>2000</id><name>PP2000</name></Student>
<Student><age>23</age><id>1000</id><name>PP1000</name></Student>
</students>
I have 2 xpaths Template XPATH = students/Student will be the template nodes, but I cannot hard code this xpath, because it will change for other XMLs, and XML is pretty dynamic, can expand (but with the same base XPATHs) So if I evaluate one more XPATH using the template node, I'm using the following code,
XPath xpathResource = XPathFactory.newInstance().newXPath();
Document xmlDocument = //creating document;
NodeList nodeList = (NodeList)xpathResource.compile("//students/Student").evaluate(xmlDocument, XPathConstants.NODESET);
for (int nodeIndex = 0; nodeIndex < nodeList.getLength(); nodeIndex++) {
Node currentNode = nodeList.item(nodeIndex);
String xpathID = "//students/Student/id";
String xpathName = "//students/Student/name";
NodeList childID = (NodeList)xpathResource.compile(xpathID).evaluate(currentNode, XPathConstants.NODESET);
NodeList childName = (NodeList)xpathResource.compile(xpathName).evaluate(currentNode, XPathConstants.NODESET);
System.out.println("node ID " +childID.item(0).getTextContent());
System.out.println("node Name " +childName.item(0).getTextContent());
}
Now the problem is, this for loop will execute for 2 times, but both time I'm getting 2000 , PP2000 as ID value. Is there any way to iterate to the child node with generic XPATH against a node. I cannot go generic XPATH against the whole XMLDocument, I have some validation to do. I want to use XML nodelist as result set rows, so that I can validate the XML value and do my stuff.
XPath xpathResource = XPathFactory.newInstance().newXPath();
Document xmlDocument = //creating document;
NodeList nodeList = (NodeList)xpathResource.compile("//students/Student/id").evaluate(xmlDocument, XPathConstants.NODESET);
for (int nodeIndex = 0; nodeIndex < nodeList.getLength(); nodeIndex++) {
Node currentNode = nodeList.item(nodeIndex);
System.out.println("node " +currentNode.getTextContent());
}
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();
}
.....
There are two types of items returned:
<LineStatus ID="0" StatusDetails="">
<BranchDisruptions/>
<Line ID="1" Name="Bakerloo"/>
<Status ID="GS" CssClass="GoodService" Description="Good Service" IsActive="true">
<StatusType ID="1" Description="Line"/>
</Status>
</LineStatus>
or
<LineStatus ID="5" StatusDetails="Severe delays">
<BranchDisruptions>
<BranchDisruption>
<StationTo ID="106" Name="High Barnet"/>
<StationFrom ID="35" Name="Camden Town"/>
<Status ID="SD" CssClass="DisruptedService" Description="Severe Delays" IsActive="true">
<StatusType ID="1" Description="Line"/>
</Status>
</BranchDisruption>
</BranchDisruptions>
<Line ID="5" Name="Northern"/>
<Status ID="SD" CssClass="DisruptedService" Description="Severe Delays" IsActive="true">
<StatusType ID="1" Description="Line"/>
</Status>
</LineStatus>
As you can see, the second element also has BranchDisruptions details filled in.
I need to build three ArrayList<String> after parsing the XML response, one containing all the LineStatus StatusDetails, one containing Line Name and one list containing all the Line Status Description.
My problem is that I want to ignore the Status from <BranchDisruption> since I don't need it. So far I have managed to get the list with all the names, but the list with statuses contains Branch statuses also.
nodelist = doc.getElementsByTagName("LineStatus");
for (int i = 0; i < nodelist.getLength(); i++)
{
Node node = nodelist.item(i);
Element Te = (Element) node;
listStatusDetails.add(Te.getAttribute("StatusDetails"));
NodeList ttLine = Te.getElementsByTagName("Line");
for (int j = 0; j < ttLine.getLength(); j++)
{
Node nNode = ttLine.item(j);
Element eElement = (Element) nNode;
listLineNames.add(eElement.getAttribute("Name"));
}
}
NodeList ttStatus = Te.getElementsByTagName("Status");
for (int j = 0; j < ttStatus.getLength(); j++)
{
Node nNode = ttStatus.item(j);
Element eElement = (Element) nNode;
listLineStatuses.add(eElement.getAttribute("Description"));
}
}
}
So as you can see in the code above, the Status is taken both from Lines and from BranchDisruption.
I want to ignore the on my parsing, so only the Status from Line is parsed.
Any ideas ?
You can use your code and alter it like this:
NodeList ttStatus = Te.getElementsByTagName("Status");
for (int j = 0; j < ttStatus.getLength(); j++)
{
Node nNode = ttStatus.item(j);
if (nNode.getParentNode().getNodeName().equals("LineStatus")) {
Element eElement = (Element) nNode;
listLineStatuses.add(eElement.getAttribute("Description"));
}
}
However the XML you are receiving isn't very nice to work with. An id should always be unique in an XML document and should not be used as a flag for the result. If you can manipulate your provider to change their XML please do.
If you succeed with that you should be able to use getElementById instead which would be both faster and more accurate. The current XML doesn't make this an option though.
i think its better to use xmlparser to parsing xml reponce.its too much easier way rather than this.
This is best demo example for xmlParsing:
reference link
I hope its useful to you.
XPath can be used for get only required statuses:
XPath path = XPathFactory.newInstance().newXPath();
NodeList nl=(NodeList)path.evaluate("LineStatus/Status/#Description", doc, XPathConstants.NODESET);
for (int i = 0; i < nl.getLength(); i++) {
System.out.println(nl.item(i).getNodeValue());
}
How can I reach to elements which have same name and recursive inclusion using Java XML? This has worked in python ElementTree, but for some reason I need to get this running in Java.
I have tried:
String filepath = ("file.xml");
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse(filepath);
NodeList nl = doc.getElementsByTagName("*/*/foo");
Example
<foo>
<foo>
<foo>
</foo>
</foo>
</foo>
You seem to be under the impression that getElementsByTagName takes an XPath expression. It doesn't. As documented:
Returns a NodeList of all the Elements in document order with a given tag name and are contained in the document.
If you need to use XPath, you should look at the javax.xml.xpath package. Sample code:
Object set = xpath.evaluate("*/*/foo", doc, XPathConstants.NODESET);
NodeList list = (NodeList) set;
int count = list.getLength();
for (int i = 0; i < count; i++) {
Node node = list.item(i);
// Handle the node
}
Given an xml document that looks like the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="agentType">STANDARD</entry>
<entry key="DestinationTransferStates"></entry>
<entry key="AgentStatusPublishRate">300</entry>
<entry key="agentVersion">f000-703-GM2-20101109-1550</entry>
<entry key="CommandTimeUTC">2010-12-24T02:25:43Z</entry>
<entry key="PublishTimeUTC">2010-12-24T02:26:09Z</entry>
<entry key="queueManager">AGENTQMGR</entry>
</properties>
I want to print the values of the "key" attribute and the element so it looks like this:
agentType = STANDARD
DestinationTransferStates =
AgentStatusPublishRate = 300
agentVersion = f000-703-GM2-20101109-1550
CommandTimeUTC = 2010-12-24T02:25:43Z
PublishTimeUTC = 2010-12-24T02:26:09Z
queueManager = AGENTQMGR
I'm able to print the node values with no problem using this code:
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile("//properties/entry/text()");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getNodeValue());
}
And I can print the values of the "key" attribute by changing the xpath expression and the node methods as follows:
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile("//properties/entry");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println(nodes.item(i).getAttributes().getNamedItem("key").getNodeValue());
}
It seems like there would be a way to get at both of these values in a single evaluate. I could always evaluate two NodeLists and iterate through them with a common index but I'm not sure they are guaranteed to be returned in the same order. Any suggestions appreciated.
What about getTextContent()? This should do the work.
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++)
{
Node currentItem = nodes.item(i);
String key = currentItem.getAttributes().getNamedItem("key").getNodeValue();
String value = currentItem.getTextContent();
System.out.printf("%1s = %2s\n", key, value);
}
For further informations please see the javadoc for getTextContent(). I hope this will help you.