XPath check for attribute and show the value - java

I need to check a bunch of .xml files for a specific permission, which is an attribute. If there is such a permission attribute i have to find out which value the attribute has.
this is my code which produces NullPointerExceptions:
public static void checkXmlPermissions(String path)
{
FileInputStream file;
try
{
file = new FileInputStream(new File(path));
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
//XPath initialisieren;
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
String expression ="//*[#permission]"; //Expression;
NodeList nodeList = (NodeList) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++)
{
String match = nodeList.item(i).getFirstChild().getNodeValue();
System.out.println(match);
}
}
catch(Exception ex)
{
System.out.println(ex);
}
}
I guess my mistake is the NodeList but I canĀ“t find a solution by my own.

change:
String match = nodeList.item(i).getFirstChild().getNodeValue();
to:
String match = nodeList.item(i).getTextContent();

Related

Is it possible to parse xml not by file name but its content (string value)?

Good Day,
Is it possible to parse XML content by not using its absolute path?
So it goes like this I have two variables:
replyInXml = "<company><staff id="1001"><firstname>yong</firstname><lastname>mook kim</lastname><nickname>mkyong</nickname><salary>100000</salary></staff></company>"
xmlFilePath = "c:\folder\file.xml"
In my Java code, I use the absolute path and I got the xml result I wanted. My question is, is it possible to parse it using the converted xml string (replyInXml) variable above.
File fXmlFile = new File(xmlFilePath);
Full Code:
public class XmlReader {
public String showProcessFlowID(String replyInXML) {
String processFlowResult = "";
try {
File fXmlFile = new File(replyInXML);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("SUIFT:TEST_ATTR_LIST");
// System.out.println("----------------------------");
for (int temp = 0; temp < nList.getLength(); temp++) {
Node nNode = nList.item(temp);
if (nNode.getNodeType() == Node.ELEMENT_NODE) {
Element eElement = (Element) nNode;
String processStep = "PROCESS STEP=" + eElement.getElementsByTagName("SUIFT:TEST_STAGE").item(0).getTextContent();
String flowID = "FLOW ID=" + eElement.getElementsByTagName("SUIFT:FLOW_ID").item(0).getTextContent();
processFlowResult = processStep + "\n" + flowID;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return processFlowResult;
}
public static void main(String args[]) {
//I want to use this but negative result since the File() parameter need xml file
String xmlContent = "<company><staff><firstname>yong</firstname><lastname>mook kim</lastname><nickname>mkyong</nickname><salary>100000</salary></staff></company>";
//This is working
String xmlPath = "C:\\folder1\\sampleReply.xml";
XmlReader processFlow = new XmlReader();
String reply = processFlow.showProcessFlowID(xmlPath);
System.out.println(reply);
}
}
Please advise.
TIA
Yes.You can user xml string to parse.
String xmlStr="";
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new ByteArrayInputStream(xmlStr.getBytes("UTF-8")));

How to dynamically assign attribute values in Xpath

I am trying to find the NodeList of the nodes containing any number of certain attributes in the XML file.
I can do the following and get the NodeList
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
DocumentBuilder db = dbf.newDocumentBuilder();
Document schDoc = db.newDocument();
InputStream schStream = new ByteArrayInputStream(sch.xml);
schDoc = db.parse(schStream)
schDoc.getDocumentElement().normalize();
XPath xpath1 = XPathFactory.newInstance().newXpath();
String expAttStr = "descendant-or-self::*[contains(#Name,'total_amt')]";
XPathExpression exprForTotalAmt = xpath1.compile(expAttStr);
NodeList totalAmtNodeList = (NodeList) exprForTotalAmt.evaluate(schDoc,XPathConstants.NODESET);
This is good.. But how can I loop and change the value of the attribute name. I tried the following and didn't work:
List<String> listOfItems= Arrays.asList("total_amt", "purchase_amt", "sales_amt");
long count = listOfItems.stream.distinct().count();
for(int i = 0; i<count; i++){
String expAttStr = "descendant-or-self::*[contains(#Name,listOfItems.get(i)]";
XPathExpression exprForTotalAmt = xpath1.compile(expAttStr);
NodeList totalAmtNodeList = (NodeList) exprForTotalAmt.evaluate(schDoc,XPathConstants.NODESET);
//some tasks
}
Would really appreciate it if anyone can point me in the right direction. Thanks.

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.

Getting null values when trying to parse an XML using XPATH in Java

When running this code in Eclipse I get only null values:
String recordsAsXML = "<vGVC:Row xmlns:vGVC=\"urn:com.versai:Bacon:GetViewContentsResponse.v1.0\"><vGVC:Column><vGVC:Value>aaa0</vGVC:Value><vGVC:ObjectName>2ff31656-b10c-11e0-99f6-e01321378d2a</vGVC:ObjectName></vGVC:Column><vGVC:ModifiedAfterQuery>false</vGVC:ModifiedAfterQuery></vGVC:Row>";
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(recordsAsXML));
Document doc = builder.parse(is);
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
XPathExpression expr = xpath.compile("//vGVC:Value/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());
}
I'm trying to extract the "aaa0" value.
Could you please help me understand what I'm doing wrong?
Thanks in advance, Michal.
You should use namespace context to let XPath know about your namespace, for example like this:
xpath.setNamespaceContext(new NamespaceContext() {
#Override public Iterator<?> getPrefixes(String namespaceURI) { return null; }
#Override public String getPrefix(String namespaceURI) { return "vGVC"; }
#Override public String getNamespaceURI(String prefix) { return "urn:com.versai:Bacon:GetViewContentsResponse.v1.0"; }
});
This should be done before calling evaluate, and if you have more than one namespace to handle, you can add them all in one implementation and use if statements to return the right prefix/URI.
More details in the javadocs here: http://download.oracle.com/javase/6/docs/api/javax/xml/namespace/NamespaceContext.html

Create XML document using nodeList

I need to create a XML Document object using the NodeList. Can someone pls help me to do this. This is my Java code:
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.*;
import org.w3c.dom.*;
public class ReadFile {
public static void main(String[] args) {
String exp = "/configs/markets";
String path = "testConfig.xml";
try {
Document xmlDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(path);
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression xPathExpression = xPath.compile(exp);
NodeList nodes = (NodeList)
xPathExpression.evaluate(xmlDocument,
XPathConstants.NODESET);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
I want to have an XML file like this:
<configs>
<markets>
<market>
<name>Real</name>
</market>
<market>
<name>play</name>
</market>
</markets>
</configs>
Thanks in advance.
You should do it like this:
you create a new org.w3c.dom.Document newXmlDoc where you store the nodes in your NodeList,
you create a new root element, and append it to newXmlDoc
then, for each node n in your NodeList, you import n in newXmlDoc, and then you append n as a child of root
Here is the code:
public static void main(String[] args) {
String exp = "/configs/markets/market";
String path = "src/a/testConfig.xml";
try {
Document xmlDocument = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(path);
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression xPathExpression = xPath.compile(exp);
NodeList nodes = (NodeList) xPathExpression.
evaluate(xmlDocument, XPathConstants.NODESET);
Document newXmlDocument = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().newDocument();
Element root = newXmlDocument.createElement("root");
newXmlDocument.appendChild(root);
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
Node copyNode = newXmlDocument.importNode(node, true);
root.appendChild(copyNode);
}
printTree(newXmlDocument);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static void printXmlDocument(Document document) {
DOMImplementationLS domImplementationLS =
(DOMImplementationLS) document.getImplementation();
LSSerializer lsSerializer =
domImplementationLS.createLSSerializer();
String string = lsSerializer.writeToString(document);
System.out.println(string);
}
The output is:
<?xml version="1.0" encoding="UTF-16"?>
<root><market>
<name>Real</name>
</market><market>
<name>play</name>
</market></root>
Some notes:
I've changed exp to /configs/markets/market, because I suspect you want to copy the market elements, rather than the single markets element
for the printXmlDocument, I've used the interesting code in this answer
I hope this helps.
If you don't want to create a new root element, then you may use your original XPath expression, which returns a NodeList consisting of a single node (keep in mind that your XML must have a single root element) that you can directly add to your new XML document.
See following code, where I commented lines from the code above:
public static void main(String[] args) {
//String exp = "/configs/markets/market/";
String exp = "/configs/markets";
String path = "src/a/testConfig.xml";
try {
Document xmlDocument = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().parse(path);
XPath xPath = XPathFactory.newInstance().newXPath();
XPathExpression xPathExpression = xPath.compile(exp);
NodeList nodes = (NodeList) xPathExpression.
evaluate(xmlDocument,XPathConstants.NODESET);
Document newXmlDocument = DocumentBuilderFactory.newInstance()
.newDocumentBuilder().newDocument();
//Element root = newXmlDocument.createElement("root");
//newXmlDocument.appendChild(root);
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
Node copyNode = newXmlDocument.importNode(node, true);
newXmlDocument.appendChild(copyNode);
//root.appendChild(copyNode);
}
printXmlDocument(newXmlDocument);
} catch (Exception ex) {
ex.printStackTrace();
}
}
This will give you the following output:
<?xml version="1.0" encoding="UTF-16"?>
<markets>
<market>
<name>Real</name>
</market>
<market>
<name>play</name>
</market>
</markets>
you can try the adoptNode() method of Document. Maybe you will need to iterate over your NodeList. You can access the individual Nodes with nodeList.item(i).If you want to wrap your search results in an Element, you can use createElement() from the Document and appendChild() on the newly created Element

Categories