Search a attribute in a xml document with java and XPath - java

i have the following method in java:
private static String getAttributValue(String attribute, String xmlResponseBody) {
String searchAttributeValue = "";
try {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
Document doc = docBuilder.parse(new InputSource(new StringReader(xmlResponseBody)));
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
try {
XPathExpression expr = xpath.compile("#" + attribute);
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodeList = (NodeList) result;
Node node = nodeList.item(0); // something wrong??
searchAttributeValue = node.getTextContent();
} catch (XPathExpressionException e) {
e.printStackTrace();
}
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (SAXException sae) {
sae.printStackTrace();
}
return searchAttributeValue;
}
I search an attribute (parameter "attribute") in a xml document (parameter "xmlResponseBody"). I would like to use XPath to solve this task. At the code, which i have comment with "// something wrong", the variable node is null. What should i do? What is the mistake in my code?
Thanks !
Marwief

It is hard to answer this without seeing the sample xml(or part of it), but you can search for an attribute using
xpath.compile("//#" + attribute)
It means search for attribute named attribute inside context node and its descendants. You can get more information here.

Related

Problem with finding XML files in IntelliJ even though they are there

First post here so bear with me, also tell me if im doing something wrong :)
I have this problem that in my IDE the application works just fine and it loads all the XML files correctly with all the data.
But when I "Build artifact" to make a release the released application.jar does NOT show all of my XML data.
After alot of googling I think it has to do with where I place my XML files and folders because when I tried to recreate the error in my IDE it gave me NullPointerException to the filepath.
This application is to be used by other people so hardcoding the absolute path is not an option.
Also good to know is that I am have two functions.
--> One function for reading only one XML file located in its own package inside src.
--> Another function used to read several XML files from a seperate package inside src.
I will paste the code below aswell as a picture showing my package structure in IntelliJ IDE.
▼ Picture of folder structure here ▼
https://i.stack.imgur.com/M9xap.png
I have tried marking ItemsXML and MonsterXML as resource in project structure but no change.
▼ Reading of one XML file below ▼
public void ReadItemXMLfile(){
try{
String fileName = "src\ItemsXML\items.xml";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(fileName);
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
XPathExpression expr = xpath.compile("/items/item"); // LOOT ID NUMBER
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
Node testNode = nodes.item(i);
if(testNode.getNodeType() == Node.ELEMENT_NODE){
Element element = (Element) testNode;
String idFromItemXml = "";
String itemNameFromItemXml = "";
idFromItemXml = element.getAttribute("id");
itemNameFromItemXml = element.getAttribute("name");
for(MonsterXML monster : monstersArrayList){
for(MonsterLootXML loot : monster.getLootableItems()){
if(loot.getId().equals(idFromItemXml)){
loot.setName(itemNameFromItemXml.substring(0, 1).toUpperCase() + itemNameFromItemXml.substring(1));
}
}
}
}
}
} catch (ParserConfigurationException parserConfigurationException) {
parserConfigurationException.printStackTrace();
} catch (IOException ioException) {
ioException.printStackTrace();
} catch (XPathExpressionException xPathExpressionException) {
xPathExpressionException.printStackTrace();
} catch (SAXException saxException) {
saxException.printStackTrace();
}
}
▼Reading of several XML files in a folder below▼
public void ReadMonsterXMLfiles(){
try{
File dir = new File("src\\MonsterXML");
if (dir.exists() && dir.isDirectory()) {
File [] files = dir.listFiles((d, name) -> name.endsWith(".xml"));
if (files != null) {
for (File file: files) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(file.getPath());
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
XPathExpression expr = xpath.compile("/monster/#name | /monster/#experience | /monster/#manacost | /monster/health/#now");
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
MonsterXML monsterXML = new MonsterXML();
monsterXML.setName(nodes.item(2).getTextContent());
monsterXML.setHealth(nodes.item(3).getTextContent());
monsterXML.setExperience(nodes.item(0).getTextContent());
monsterXML.setManaToSummon(nodes.item(1).getTextContent());
monsterXML.setName(monsterXML.getName().substring(0, 1).toUpperCase() + monsterXML.getName().substring(1));
// MONSTER LOOT (ID) AND MONSTER LOOT (DROPCHANCE%)
expr = xpath.compile("/monster/loot//item"); // LOOT ID NUMBER
result = expr.evaluate(doc, XPathConstants.NODESET);
nodes = (NodeList) result;
MonsterLootXML monsterLootXML = null;
for (int i = 0; i < nodes.getLength(); i++) {
Node testNode = nodes.item(i);
if(testNode.getNodeType() == Node.ELEMENT_NODE){
Element element = (Element) testNode;
monsterLootXML = new MonsterLootXML();
monsterLootXML.setId(element.getAttribute("id"));
monsterLootXML.setLootChance(element.getAttribute("chance"));
monsterLootXML.setLootChance(Calculations.correctDropChanceNumber(monsterLootXML.getLootChance()));
if(element.hasAttribute("countmax")){
monsterLootXML.setAmount(element.getAttribute("countmax"));
}
else{
monsterLootXML.setAmount("1");
}
monsterXML.addLootableItems(monsterLootXML);
}
}
monstersArrayList.add(monsterXML);
}
}
}
}
catch (Exception e) {
e.printStackTrace();
}
}
If anyone knows this well I would love to get some tutoring on discord if possible :)
Thanks you all!
Answer to this is to include the XML files in your folder (outside of your .jar) and then just refeering to that XML file when starting the application.
If you want to have the XML files inside of your .jar and load them from there you need to look up "getResourceAsStream".

Xpath - why only 1 value returned?

Given the xml snippet:
<AddedExtras>
<AddedExtra Code="1234|ABCD" Quantity="1" Supplier="BDA"/>
<AddedExtra Code="5678|EFGH" Quantity="1" Supplier="BDA"/>
<AddedExtra Code="9111|ZXYW" Quantity="1" Supplier="BDA"/>
</AddedExtras>
The following XPath expression:
//*["AddedExtra"]/#Code
when run through a checker evaluates to:
Attribute='Code=1234|ABCD'
Attribute='Code=5678|EFGH'
Attribute='Code=9111|ZXYW'
Why then, does the following code only return the first line?
private String allCodes = "//*["AddedExtra"]/#Code";
get my XML from system and parse it into a Doc:
public Document parseResponse(String response){
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder;
Document doc = null;
//Create a document reader and an XPath object
try {
builder = factory.newDocumentBuilder();
doc = builder.parse(new InputSource((new StringReader(response))));
} catch (ParserConfigurationException | org.xml.sax.SAXException | IOException e) {
e.printStackTrace();
}
return doc;
}
Get the new doc:
public Document getParsedResponse(String response) {
return parseResponse(response);
}
Return the Xpath value from the doc:
public String getAllCodeOptions(String response){
Document doc = getParsedResponse(response);
return getNodeValueFromNodeList(doc, allCodes);
}
new method to read the XML nodes:
public String getNodeValueFromNodeList(Document doc, String expression){
NodeList nodeList = null;
String nodes = null;
try {
nodeList = (NodeList) xpath.compile(expression).evaluate(doc, XPathConstants.NODESET);
} catch (XPathExpressionException e) {
e.printStackTrace();
}
for(int i=0; i < nodeList.getLength(); i++){
Node node = nodeList.item(i);
nodes = node.getNodeValue();
}
return nodes;
}
returns:
Attribute='Code=1234|ABCD'
You would require to use right evaluate method which takes return type as an argument. Something like below,
NodeSet result = (NodeSet)e.evaluate(e, doc, XPathConstants.NODESET);
for(int index = 0; index < result.getLength(); index ++)
{
Node node = result.item(index);
String name = node.getNodeValue();
}
The problem is that you are asking for only one value.
Try this:
NodeList nodeList = (NodeList)e.evaluate(doc, XPathConstants.NODESET);
for multiple values.
See http://viralpatel.net/blogs/java-xml-xpath-tutorial-parse-xml/ for a tutorial.

Parsing xml for single value with XPath returns empty string

I'm trying to get this value B006PF20EI in this XML
<ItemSearchResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2011-08-01">
<OperationRequest>...</OperationRequest>
<Items>
<Request>...</Request>
<TotalResults>8</TotalResults>
<TotalPages>1</TotalPages>
<MoreSearchResultsUrl>...</MoreSearchResultsUrl>
<Item>
<ASIN>B006PF20EI</ASIN>
I'm using XPaths like so
public String parseXml(String xmlString){
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document dDoc = builder.parse(new InputSource(new StringReader(xmlString)));
XPath xPath = XPathFactory.newInstance().newXPath();
//Node node = (Node) xPath.evaluate("/Items/Item/ASIN", dDoc, XPathConstants.NODE);
//System.out.println(node.getNodeValue());
String value = xPath.evaluate("/ItemSearchResponse/resp/status", dDoc);
return value;
} catch (Exception e) {
Log.e("MYAPP", "exception", e);
return null;
}
}
But it looks like the method is just returning an emptry string
use the good path:
/ItemSearchResponse/Items/Item/ASIN

parsing xml string in java

I have been trying to use code I found from other posts, to parse an xml string but when trying to get to the node elements I keep getting null values. Can someone see the error or something I am missing?
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(post));
Document doc;
try {
doc = db.parse(is);
doc.getDocumentElement().normalize();
Element root = doc.getDocumentElement();
NodeList nodes = root.getElementsByTagName("entry");
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
the root element is null and nodelist null as well. The XML post starts with:
<entry xmlns="http://www.w3.org/2005/Atom"
xmlns:activity="http://activitystrea.ms/spec/
1.0/" xmlns:service="http://activitystrea.ms/
service-provider" xmlns:thr="http://purl.org/syndication/thread/1.0"
xmlns:gnip="http://www.post.com/schemas/2010"
xmlns:geo="http://www.georss.org/georss" xmlns:poco="http://portablecontacts.net/spec/1.0">
<id>...
EDIT:
NodeList nodes.. //The value of the local nodes is not used
[entry: null]
// it skips the following lines...
for(int i=0; i < nodes.getLength() - 1; i++){
System.out.println(nodes.item(i).toString());
}
replace NodeList nodes = root.getElementsByTagName("entry");
by NodeList nodes = root.getChildNodes();

XML parsing using XPath in Java

Hi!
I've spent some time to parse an XML document with XPath. It seeams to be a simple task but I got in troubles since the begining.
My code is :
public class QueryXML3 {
public static void main(String[] args) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder;
Document doc = null;
try {
builder = factory.newDocumentBuilder();
//doc = builder.parse("SampleExample.xml");
InputStream is = QueryXML3.class.getClassLoader().getResourceAsStream("SampleXml.xml");
doc = builder.parse(is);
XPathFactory xpathFactory = XPathFactory.newInstance();
// Create XPath object
XPath xpath = xpathFactory.newXPath();
Node parNode = getParameterNode(doc, xpath);
System.out.println("parameter node:" + parNode);
NodeList res = getParameterNodeList(doc, xpath );
System.out.println("List of nodes" + res);
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
}
public static Node getParameterNode(Document doc, XPath xpath) {
Node res = null;
try {
res = (Node) xpath.evaluate("/definitions/process", doc, XPathConstants.NODE);
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return res;
}
public static NodeList getParameterNodeList(Document doc, XPath xpath) {
NodeList nodeList = null;
try {
nodeList = (NodeList) xpath.evaluate("/definitions/process", doc, XPathConstants.NODESET);
for (int i = 0; i > nodeList.getLength(); i++) {
System.out.print(nodeList.item(i).getNodeName() + " ");
}
} catch (XPathExpressionException e) {
e.printStackTrace();
}
return nodeList;
}
}
As a result i get this:
parameter node:[process: null]
List of nodes com.sun.org.apache.xml.internal.dtm.ref.DTMNodeList#2f17aadf
I just want to output all the nodes of my xml file and theire attributes...
You are really asking how to serialize an Element to a string - use either a Transformer or DOMImplementationLS.
The NodeList type has no toString() contract and the implementation does not override the default Object.toString(). You need to iterate over the nodes and serialize each Element as above.
You could easily parse an XML file in java using a 3rd party package such as JSoup or JDom.
As an example, here is some simple output of an XML files elements using JSoup:
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
Java code printing all elements and the selected <from>-element:
String xml = "<note>\n"
+ "<to>Tove</to>\n"
+ "<from>Jani</from>\n"
+ "<heading>Reminder</heading>\n"
+ "<body>Don't forget me this weekend!</body>\n"
+ "</note>";
Document doc = Jsoup.parse(xml, "", Parser.xmlParser());
for (Element e : doc.children()) {
System.out.println(e);
}
Element fromElement = doc.select("from").first();
System.out.println("\nThis is the <from>-element content:\n" + fromElement);

Categories