Maintaining count of XML elements using Xpath - java

I am a beginner in using Java programming particularly using Xpath to parse an XML file.
I am trying to develop a system that routes flights according to their weightings. I want to:
Maintain a count of flights for each location;
The system should accept a location and return the number and country to route a flight to. For every 4 flights to Japan, route the next 2 flights to China then route the next 2 flights to India and loop and to return count, continent, location name, country and weight.
I would appreciate any assistance please.
I can pass the XML data of and retrieve the different element nodes using Xpath. I attempted using SAX and STAX but prefered this method as it was clear and concise when constructing the expressions.
XML File Example:
<continent>
<location name = "asia">
<country>Japan</country>
<code>0000011111</code>
<weight>10</weight>
</location>
<location name = "asia">
<country>China</country>
<code>0000022222</code>
<weight>1</weight>
</location>
</continent>
Java Sample Code:
public static void main(String[] args) {
try {
FileInputStream file = new FileInputStream(new File("c:/continents.xml"));
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
System.out.println("*************************");
String expression = "/continent/location";
System.out.println(expression);
String name = xPath.compile(expression).evaluate(xmlDocument);
System.out.println(name);
System.out.println("**********Parse XML File***************");
expression = "/continent/location/country|//number|//weight";
System.out.println(expression);
NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
System.out.println(nodeList.item(i).getFirstChild().getNodeValue());
}
System.out.println("*************************");
expression = "/continent/location[#name='asia']/number";
System.out.println(expression);
nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
System.out.println(nodeList.item(i).getFirstChild().getNodeValue());
}
System.out.println("*************************");
expression = "//location[country='China']";
System.out.println(expression);
Node node = (Node) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODE);
if(null != node) {
nodeList = node.getChildNodes();
for (int i = 0;null!=nodeList && i < nodeList.getLength(); i++) {
Node nod = nodeList.item(i);
if(nod.getNodeType() == Node.ELEMENT_NODE)
System.out.println(nodeList.item(i).getNodeName() + " : " + nod.getFirstChild().getNodeValue());
}
}
}

I’m not sure I understand your goal, but if you just want to count how many flights are to a particular country, you can count the matching elements:
NodeList matches = (NodeList) xPath.evaluate(
"//country[text()='" + country + "']",
xmlDocument,
XPathConstants.NODESET);
int matchCount = matches.getLength();

Related

XML parsing to Java - getting root attribute value

I'm having a slight problem with XML parsing.
I'm creating a function where the parameter is a certain "element" from the XML file.
When found, I want to return the value of the root attribute.
Here's my code:
FileInputStream file = new FileInputStream(new File("C:\\Users\\Grizzly\\Java\\Projet_16_17-20161214\\bdd.xml"));
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(file);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("type");
for (int temp = 0; temp < nList.getLength(); temp++)
{
Node nNode = nList.item(temp);
if(nNode.toString().equalsIgnoreCase(element))
{
Element eElement = (Element) nNode;
System.out.println("Taxe= "+ eElement.getAttribute("taxe"));
}
}
}
Any idea on how to do this?
Here's my XML file:
<?xml version="1.0"?>
-<types>
-<type id="Nourriture" taxe="0.1">
<element>pomme</element>
<element>fraise</element>
<element>fromage</element>
<element>viande rouge </element>
</type>
-<type id="Matiere Premiere" taxe="0.2">
<element>fer</element>
<element>polypropylene</element>
</type>
-<type id="Element Solide" taxe="0.3">
<element>voiture</element>
<element>planche surf</element>
<element>pistolet</element>
</type>
</types>
In my code, I tried to get the elements of a certain node from the nodelist and then compare it to the the string "element" which is the input of the user, and if they match it will check the attribute value of taxe linked to it.
Thanks in advance.
EDIT: I'm getting closer to what I need:
NodeList nList = doc.getElementsByTagName("type");
for (int temp = 0; temp < nList.getLength(); temp++)
{
Node nNode = nList.item(temp);
NodeList nChildren = nNode.getChildNodes();
Element eElement = (Element) nNode;
for(int i = 0; i < nChildren.getLength(); i++)
{
String onElement = eElement.getElementsByTagName("element").item(i).getTextContent();
if(onElement.equalsIgnoreCase(element))
{
System.out.println("id : " + eElement.getAttribute("id"));
System.out.println("taxe : " + eElement.getAttribute("taxe"));
break;
}
}
}
But it's only reading the first element... and item(i) isn't working.
Any idea?
If I understand you correctly, you are trying to fetch specific attributes (id and taxe) of all the document nodes having at least one child element with specific name (element).
Although the problem can be solved by iterating the DOM and keeping the states, I would rather delegate this task to XPath. A code with XPath will look cleaner and be more maintainable. For example, in order to fetch all elements having attributes id and taxe and a child element element you can use an XPath expression like //*[#id and #taxe element]. The matching nodes are fetched in a single line. You can simply iterate the nodes and collect the attributes as shown in the following example.
Example
public static void main(String args[]) {
String element = args.length > 0 ? args[0] : "element";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
FileInputStream file = new FileInputStream(new File("/some/file.xml"));
Document doc = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
String expression = "//*[#id and #taxe and " + element + "]";
NodeList nodeList = (NodeList) xPath.compile(expression)
.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
NamedNodeMap attributes = node.getAttributes();
for (int j = 0; j < attributes.getLength(); j++) {
Node aNode = attributes.item(j);
System.out.printf(
"%s: %s\n",
aNode.getNodeName(),
aNode.getNodeValue()
);
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
Sample Output
id: Nourriture
taxe: 0.1
id: Matiere Premiere
taxe: 0.2
id: Element Solide
taxe: 0.3
Note, the sample above prints all attributes of the parent element. If you want to print only specific ones, you can, obviously, add a trivial check like this:
String aName = aNode.getNodeName();
if (aName.equals("taxe")) { // ...
But you can actually filter out the attributes with XPath:
String expression = "//*[ " + element + "]/#*[name() = 'id' or name() = 'taxe']";
NodeList nodeList = (NodeList) xPath.compile(expression)
.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
System.out.printf("%s: %s\n", node.getNodeName(), node.getNodeValue());
}
The XPath expression above fetches all attribute nodes having names equal to whether id, or taxe. If you want all attributes, simply remove the last condition:
String expression = "//*[ " + element + "]/#*";

XML attribute Parsing

When parsing the xml, I want to retrieve the token value:
PCWTJ87OXNnGhwzvzqvbhepi2qQM6PhMdNHn7V9UuVw|
But I am currently getting the related:
Found attribute: expiry with value: 2014-10-29T22:20:00Z
xml file:
<?xml version="1.0"?>
<Inrix responseId="63448807-78d3-4ee8-90d6-a8b64abff8fc" statusText="" statusId="0" createdDate="2014-10-29T21:21:55Z" versionNumber="5.4" copyright="Copyright INRIX Inc." docType="GetSecurityToken">
<AuthResponse>
<AuthToken expiry="2014-10-29T22:20:00Z">PCWTJ87OXNnGhwzvzqvbhepi2qQM6PhMdNHn7V9UuVw|</AuthToken>
<ServerPath>devzone.inrix.com/traffic/inrix.ashx</ServerPath>
<ServerPaths>
<ServerPath region="NA" type="API">http://na.api.inrix.com/Traffic/Inrix.ashx</ServerPath>
<ServerPath region="NA" type="TTS">http://na-rseg-tts.inrix.com/RsegTiles/tile.ashx</ServerPath>
</ServerPaths>
</AuthResponse>
</Inrix>
This is the code I wrote to parse the xml file above:
DocumentBuilderFactory factory =DocumentBuilderFactory.newInstance();
DocumentBuilder builder =factory.newDocumentBuilder();
Document document = builder.parse(new File(inputfile));
document.getDocumentElement().normalize();
NodeList AuthTokens = document.getElementsByTagName("AuthToken");
//NodeList AuthTokens = document.getElementsByTagName("ServerPath");
int num = AuthTokens.getLength();
for (int i=0; i<num;i++){
Element node = (Element) AuthTokens.item(i);
NamedNodeMap attributes = node.getAttributes();
int numAttrs = attributes.getLength();
for (int j=0; j<numAttrs;j++){
Attr attr = (Attr) attributes.item(j);
String attrName = attr.getNodeName();
String attrValue = attr.getNodeValue();
System.out.println(attr.getParentNode());
System.out.println("Found attribute: " + attrName + " with value: " + attrValue);
}
}
How do I get the correct value?
I believe you want the contents of the node, not its' attributes. Change your Element to Node and then you can call Node.getTextContent()
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File(inputfile));
document.getDocumentElement().normalize();
NodeList AuthTokens = document.getElementsByTagName("AuthToken");
// NodeList AuthTokens = document.getElementsByTagName("ServerPath");
int num = AuthTokens.getLength();
for (int i = 0; i < num; i++) {
Node node = AuthTokens.item(i);
String token = node.getTextContent();
System.out.println(token);
}
Output is (as requested)
PCWTJ87OXNnGhwzvzqvbhepi2qQM6PhMdNHn7V9UuVw|

Reading multi-node and attribute XML in Java

My XML is as follows:-
<myxml>
<resource name='book'>
<acl>
<ace person='bob' rights='rw' />
<ace person='john' rights='w' />
</acl>
</resource>
<resource name='dvd'>
<acl>
<ace person='bob' rights='w' />
</acl>
</resource>
</myxml>
I am having trouble reading this XML document.
Here is the code I tried.
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory
.newDocumentBuilder();
Document document = documentBuilder.parse(new File(fileName));
Element rootElement = xmlDocument.getDocumentElement();
NodeList resourceList= rootElement.getElementsByTagName("resource");
for (int i = 0; i < resourceList.getLength(); i++) {
Node node = resourceList.item(i);
Element element = (Element) node;
String resourceName= element.getAttribute("name");
}
Basically I want to print like "this book can be used by this person with xyz permission".
I can get the name of the book by String objectName= element.getAttribute("name"). After this I can't go.
I tried by getting child nodes but keep on getting nulls.
Any suggestions?
One option is use element.getElementsByTagName("ace") to retrieve the ace elements you're looking for:
NodeList aceList = element.getElementsByTagName("ace");
for(int j= 0; j < aceList.getLength(); j++){
Element ace = (Element) aceList.item(j);
String person = ace.getAttribute("person");
}
You just need another for loop nested inside to process <ace> elements.
NodeList resourceList = rootElement.getElementsByTagName("resource");
for (int i = 0; i < resourceList.getLength(); i++) {
Element resource = (Element) resourceList.item(i);
String book = resource.getAttribute("name");
NodeList aceList = resource.getElementsByTagName("ace");
for (int j = 0; j < aceList.getLength(); j++) {
Element ace = (Element) aceList.item(j);
System.out.println("'" + book + "' can be used by '"
+ ace.getAttribute("person") + "' with '"
+ ace.getAttribute("rights") + "' permission.");
}
}
Output :
'book' can be used by 'bob' with 'rw' permission.
'book' can be used by 'john' with 'w' permission.
'dvd' can be used by 'bob' with 'w' permission.

Fill an array with objects from XML [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I have a XML file that I am trying to read and transform into objects. I want to transform and put all the locations in a array filled with Location objects wich are defined by a film id, a date and a amount.
Here is my XML file :
Here is my code to scan the location XML section :
public void findLocations() throws ParseException {
NodeList nList = document.getElementsByTagName("location");
Location[] locations = new Location[nList.getLength()];
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
locations[temp] = new Location(getTagValue("filmid", eElement), dateChanger(getTagValue("date", eElement)), getTagValue("amount", eElement));
System.out.println(locations[temp].getAmount()); //Outputs the good values.
}
}
System.out.println(locations[0].getAmount()); //Output : 5$
System.out.println(locations[1].getAmount()); //Output : 5$
System.out.println(locations[2].getAmount()); //Output : 5$
}
private static String getTagValue(String sTag, Element eElement) {
NodeList nlList = eElement.getElementsByTagName(sTag).item(0).getChildNodes();
Node nValue = (Node) nlList.item(0);
return nValue.getNodeValue();
}
The problem seems that my array is getting filled 3 times with the same location and ends up filled 3 time with the last location. The objects otherwise are well formed, so I imagine I got that part right.
You could use XPath instead...
public class TestXML03 {
public static void main(String[] args) {
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(false);
DocumentBuilder builder = factory.newDocumentBuilder();
Document xmlDoc = builder.parse(new File("Test.xml"));
Node root = xmlDoc.getDocumentElement();
XPathFactory xFactory = XPathFactory.newInstance();
XPath xPath = xFactory.newXPath();
XPathExpression xExpress = xPath.compile("/file/location");
NodeList nodes = (NodeList) xExpress.evaluate(root, XPathConstants.NODESET);
System.out.println("Found " + nodes.getLength() + " location nodes");
System.out.println("");
for (int index = 0; index < nodes.getLength(); index++) {
Node node = nodes.item(index);
xExpress = xPath.compile("filmid");
Node filmIDNode = (Node) xExpress.evaluate(node, XPathConstants.NODE);
System.out.println(filmIDNode.getNodeName() + " = " + filmIDNode.getTextContent());
xExpress = xPath.compile("date");
Node dateNode = (Node) xExpress.evaluate(node, XPathConstants.NODE);
System.out.println(dateNode.getNodeName() + " = " + dateNode.getTextContent());
xExpress = xPath.compile("amount");
Node amountNode = (Node) xExpress.evaluate(node, XPathConstants.NODE);
System.out.println(amountNode.getNodeName() + " = " + amountNode.getTextContent());
System.out.println("");
}
} catch (Exception exp) {
exp.printStackTrace();
}
}
}
Which outputs...
Found 3 location nodes
filmid = 100
date = 2013-01-11
amount = 4.00$
filmid = 200
date = 2013-01-13
amount = 9.00$
filmid = 334
date = 2013-01-23
amount = 5.00$
Updated After Feed-back
The Location class is maintaining a static reference to it's class fields, this means that changing the value for the field will change it for all instances of that class.
Remove the static references and it should solve the problem.
Your source is working perfectly. Simply modifying your source to output tags as below.
public static void findLocations(Document document) throws ParseException {
NodeList nList = document.getElementsByTagName("location");
Location[] locations = new Location[nList.getLength()];
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
System.out.println(getTagValue("filmid", eElement));
System.out.println(getTagValue("date", eElement));
System.out.println(getTagValue("amount", eElement));
System.out.println();
}
}
}
I got the proper output
100
2013-01-11
4.00$
200
2013-01-13
9.00$
334
2013-01-23
5.00$
Check if your XML input is proper.

Parsing attribute in XML with DOM parser

I am currently parsing XML, but im not quite sure how to parse the "status" attribute of "message":
<message status="test"> <text>sometext</text> <msisdn>stuff</msisdn> </message>
Here is the code, i have cut off everything unnecessary:
NodeList nodeLst = doc.getElementsByTagName("message");
for (int s = 0; s < nodeLst.getLength(); s++) {
Node fstNode = nodeLst.item(s);
if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
Element fstElmnt = (Element) fstNode;
NodeList numberNmElmntLst = fstElmnt
.getElementsByTagName("msisdn");
Element numberNmElmnt = (Element) numberNmElmntLst.item(0);
NodeList numberNm = numberNmElmnt.getChildNodes();
String phoneNumber = ((Node) numberNm.item(0))
.getNodeValue().substring(2);
NodeList txtNmElmntLst = fstElmnt
.getElementsByTagName("text");
Element txtNmElmnt = (Element) txtNmElmntLst.item(0);
NodeList txtNm = txtNmElmnt.getChildNodes();
String text = ((Node) txtNm.item(0)).getNodeValue();
NodeList rcvNmElmntLst = fstElmnt
.getElementsByTagName("received");
Element rcvNmElmnt = (Element) rcvNmElmntLst.item(0);
NodeList rcvNm = rcvNmElmnt.getChildNodes();
String recievedDate = ((Node) rcvNm.item(0)).getNodeValue();
}
}
Can anyone guide me how this is done?
Thanks in advance.
Node.getAttributes()
NamedNodeMap attributes = fstElmnt.getAttributes();
for (int a = 0; a < attributes.getLength(); a++)
{
Node theAttribute = attributes.item(a);
System.out.println(theAttribute.getNodeName() + "=" + theAttribute.getNodeValue());
}
You could avoid traversing if you use XPATH to retrieve the data. Read this tutorial.
I have been playing with Apache Xerces for parsing DOM. But it was horrible tasks. If you could, take a look at jsoup.
So, if your question has an answer in Jsoup, it would be:
node.attr("status")

Categories