Xpath query from a specific node - java

The usual queries that I'm currently supporting are from the root , meaning :
public Object evaluate(String expression, QName returnType) {...}
Now I want to do the Xpath query starting from some given Node , e.g. :
public Object evaluate(String expression, Node source, QName returnType) { ? }
Then , If my usual queries look like this (here's an exmaple) :
//load the document into a DOM Document
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("books.xml");
//create an XPath factory
XPathFactory factory = XPathFactory.newInstance();
//create an XPath Object
XPath xpath = factory.newXPath();
//make the XPath object compile the XPath expression
XPathExpression expr = xpath.compile("/inventory/book[3]/preceding-sibling::book[1]");
//evaluate the XPath expression
Object result = expr.evaluate(doc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
//print the output
System.out.println("1st option:");
for (int i = 0; i < nodes.getLength(); i++) {
System.out.println("i: " + i);
System.out.println("*******");
System.out.println(nodeToString(nodes.item(i)));
System.out.println("*******");
What kind of changes would I need for making this happen for the above method (public Object evaluate(String expression, Node source, QName returnType);)
Thanks!

Related

How do I return a subsection of an XML request based on an XPath expression

I have written code that enables me to a subsection of an xml request based on a given XPath, however, it is only the value between the tags that are returned and not the tags.
I want both values and elements to be returned based on a given xpath.
For example, in this xml:
?xml version="1.0"?>
<company>
<staff1>
<name>john</name>
<phone>465456433</phone>
<email>gmail1</email>
<area>area1</area>
<city>city1</city>
</staff1>
<staff2>
<name>mary</name>
<phone>4655556433</phone>
<email>gmail2</email>
<area>area2</area>
<city>city2</city>
</staff2>
<staff3>
<name>furvi</name>
<phone>4655433</phone>
<email>gmail3</email>
<area>area3</area>
<city>city3</city>
</staff3>
</company>
my XPath would only return the value of the first staff element i.e.
John
465456433
gmail1
area1
city1
It does not return the tags associated to it i.e, it should return the following:
<staff1>
<name>john</name>
<phone>465456433</phone>
<email>gmail1</email>
<area>area1</area>
<city>city1</city>
</staff1>
Here is my code:
InputSource inputSource = new InputSource(new StringReader(xmlString));
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
String RecordCategory;
Document doc = documentBuilderFactory.newDocumentBuilder().parse(inputSource);
// Create XPathFactory object
XPathFactory xpathFactory = XPathFactory.newInstance();
// Create XPath object
XPath xpath = xpathFactory.newXPath();
System.out.println("TESTING XPATH");
xpath.setNamespaceContext(new NamespaceContext() {
#Override
public String getNamespaceURI(String prefix) {
...
});
XPathExpression expr = xpath.compile("//staff1[1]");
Staff1 = (String) expr.evaluate(doc,XPathConstants.STRING);
System.out.println("staff1: " + staff1);
Anyone have any idea on what I could do to resolve this issue?
Your Java call to XPathExpression.evaluation() is returning the string value of the node selected by your XPath expression. If you instead want to return the node selected by your XPath expression, change
Staff1 = (String) expr.evaluate(doc, XPathConstants.STRING);
to
Node node = (Node) expr.evaluate(doc, XPathConstants.NODE);
See this answer for how to pretty print node.

How to get Nth parent for an element in xml using Java

I am using w3c dom library to parse XML. Here I need 3rd parent of element .For example in below XML I am using element.getParentNode()
Input XML
<abc cd="1">
<weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0">
<current_conditions>
<condition data="Clear">
<item abc ="1" />
</condition>
<temp_f data="49"/>
<temp_c data="9"/>
</current_conditions>
</weather>
</abc>
I have Element eleItem= /item and have to get to parent /weather I am doing it as :
(Element) eleItem.getParentNode().getParentNode().getParentNode();
Is there any other method or using xpath as this doesn't seem to be the right way ?
something likegetXPathParent(eleItem, "../../..")
You are almost there. You could use XPathFactory of java like below :
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse( new File( "input.xml" ) );
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
XPathExpression expr = xpath.compile ( "//item/../../..");
Object exprValue = expr.evaluate( doc, XPathConstants.NODE );
if ( exprValue != null && exprValue instanceof Node )
{
Node weatherNode = (Node)exprValue;
System.out.println( weatherNode.getNodeName() );
}
How it works?
The xpath //item/../../.. recursively searches for element item and gets its 3rd level parent.
The XPathConstants.NODE in the evaluate tells Java XPath engine to retrieve it as a Node.
Output will be :
weather
EDIT:
- If you have an element as input :
The following code should give the 3rd parent, where element is item.
public Node getParentNodeUsingXPath( Element element )
{
Node parentNode = null;
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
String nodeName = element.getNodeName();
String expression = "//" + nodeName + "/../../..";
Object obj = xpath.evaluate(expression, element, XPathConstants.NODE );
if ( obj != null )
{
parentNode = (Node)obj;
}
return parentNode;
}

Java XML XPath Full XML

got a little problem. I have the following code:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse("result1.xml");
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
XPathExpression expr = xpath.compile("//element");
String elements = (String) expr.evaluate(doc, XPathConstants.STRING);
What i get :
jcruz0#exblog.jp
Cheryl
Blake
195115
What i want:
<person>
<email>jcruz0#exblog.jp</email>
<firstname>Cheryl</firstname>
<lastname>Blake</lastname>
<number>195115</number>
</person>
So as you can see i want the full XML tree. Not just the NodeValue.
Maybe somebody knows the trick.
Thanks for any help.
You got the string value of the selected XML element because you specified XPathConstants.STRING to XPathExpression.evaluate().
Instead, specify a return type of XPathConstants.NODE if you know for sure that your XPath will select a single element,
String elements = (String) expr.evaluate(doc, XPathConstants.NODE);
or XPathConstants.NODESET for multiple elements, which you would then iterate over to process as necessary.
Something like this can be done.
XPathExpression expr = xpath.compile("/person");
NodeList elements = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < elements.getLength(); i++) {
// the person node
System.out.println(elements.item(i).getNodeName());
for (int x = 0; x < elements.item(i).getChildNodes().getLength(); x++) {
// the elements under person
if (elements.item(i).getChildNodes().item(x).getNodeType() == Node.ELEMENT_NODE) {
System.out.println("\t" + elements.item(i).getChildNodes().item(x).getNodeName() + " - " + elements.item(i).getChildNodes().item(x).getTextContent());
}
}
}
Output
person
email - jcruz0#exblog.jp
firstname - Cheryl
lastname - Blake
number - 195115
You can use the nodes to do what you want, or wrap them in < and > if you just want to print them.

How read more XSD schemas with Xpath?

I have 2 XSD schemas first.xsd and second.xsd
In first.xsd is:
<xs:include schemaLocation="second.xsd" />
and I want read elements in second.xsd.
I have defined:
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(new FileInputStream("first.xsd"));
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList result1 = null;
result1 = (NodeList) xPath.compile("//element[#name='List']").evaluate(xmlDocument, XPathConstants.NODESET);
for (int k = 0; k < result1.getLength(); k++) {
Element ele = (Element)result1.item(k);
System.out.println(ele.getAttribute("type")); }
Problem is program didnt find element list in second.xsd.
Can I define some as this?
Document xmlDocument = builder.parse(new FileInputStream("first.xsd","second.xsd"));
Is something as LSResourceResolver but that is for validation.
Can I use it for my code?
Thank you for advices.

How do I resolve two nodes which have the same name but under different parents?

<PublicRecords>
<USBankruptcies>
<USBanktruptcy>...<USBankruptcy>
<CourtId>...</CourtId>
<USBanktruptcy>...<USBankruptcy>
<CourtId>...</CourtId>
</USBankruptcies>
<USTaxLiens>
<USTaxLien>...<USTaxLien>
<CourtId>...</CourtId>
<USTaxLien>...<USTaxLien>
<CourtId>...</CourtId>
</USTaxLiens>
<USLegalItems>
<USLegalItem><USLegalItem>
<CourtId></CourtId>
<USLegalItem><USLegalItem>
<CourtId></CourtId>
</USLegalItems>
</PubicRecords>
I am using a combination of doc and xpath objects to extract the attributes and node contents.
NodeList bp = doc.getElementsByTagName("USBankruptcy");
NodeList nl = doc.getElementsByTagName("CourtId");
long itrBP;
for (itrBP = 0; itrBP < bp.getLength(); itrBP++ )
{
Element docElement = (Element) bp.item(itrBP);
Element courtElement = (Element) nl.item(itrBP);
NodeList df = docElement.getElementsByTagName("DateFiled");
if(df.getLength() > 0)
{
dateFiled = nullIfBlank(((Element)df.item(0)).getFirstChild().getTextContent());
dateFiled = df.format(dateFiled);
}
But, when I say get elements of tag name CourtID, it will get all the CourtIDs, not just the ones under USBankruptcy.
Is there any way to specify the parent?
I tried NodeList nl = doc.getElementsByTagName("USBankruptcies/CourtId");
It gave me a dom error on run time.
Rather than calling the getElementsByTagName("CourtId") method on the Document, call it on the child Element (in your case, the <USBankruptcies> element).
NodeList bankruptcyNodes = doc.getElementsByTagName("USBankruptcies");
Element bankruptcyElement = (Element) bankruptcyNodes.item(0);
NodeList bankruptcyCourtNodes = bankruptcyElement.getElementsByTagName("CourtId");
// etc...
Please find the code here:
DocumentBuilderFactory domFactory = DocumentBuilderFactory
.newInstance();
domFactory.setNamespaceAware(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse("test.xml");
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile("*//USBankruptcies/CourtId");
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));
}

Categories

Resources