Stuck with XPath - java

Can somebody find what is wrong with this code. It always returns o nodes no matter whatever XPath I chose
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true);
domFactory.setIgnoringComments(true);
domFactory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document dDoc = builder.parse("P:/MyBooks.xml");
NodeList myNodes = (NodeList) xpath.evaluate("//Title", dDoc, XPathConstants.NODESET);
System.out.println(myNodes.getLength());
MyBookx.xml is:
<?xml version="1.0" encoding="UTF-8"?>
<Books>
<Title attrib="title1"/>
<Title attrib="title2"/>
<Title attrib="title3"/>
</Books>

I was doing a big mistake. My xml doc was using default namespace while I am setting NamespaceAware(true) in docFactory. So I set NamespaceAware(false) and my problem is solved

Related

How to properly pass an object from XML using Xpath

I will try to describe my issue.
I have the XML document with next structure (don't look at Russian text; it is ok) :
<Books>
<Book ganre="fantasy">
<bookId>FD46</bookId>
<bookName>Меч предназначения</bookName>
<bookAuthor>Анджей Сапковский</bookAuthor>
<bookYear>1994</bookYear>
<bookAvailable>false</bookAvailable>
</Book>
<Book ganre="fantasy">
<bookId>0RD7</bookId>
<bookName>Башня ласточки</bookName>
<bookAuthor>Анджей Сапковский</bookAuthor>
<bookYear>1997</bookYear>
<bookAvailable>false</bookAvailable>
</Book>
<Book ganre="action">
<bookId>709F</bookId>
<bookName>Автостопом по галактике</bookName>
<bookAuthor>Дуглас Адамс</bookAuthor>
<bookYear>1979</bookYear>
<bookAvailable>false</bookAvailable>
</Book>
</Books>
Trying to find element by bookID with help of this Xpath
FileInputStream fileInputStream = new FileInputStream("Test/Books.xml");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(fileInputStream);
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();
Node node = (Node) xPath
.evaluate("//Book[bookId/text()='" + bookID + "']", document.getDocumentElement(), XPathConstants.NODE);
bookID - this is user input (for eg like this)
Scanner sc = new Scanner(System.in, "cp866");
String bookID;
bookID = sc.nextLine();
So idea is to return from xml node from THIS object that we found with current id in a String <bookName></bookName><bookAuthor></bookAuthor> so I can put into another xml.
Like
String takenBookName = new XMLDocument(xml).xpath("/Books/Book/bookName/text").get(0); //it will doesnt work ;)
Must work for you.
//Book[bookId/text()='709F']/bookName/text()

How to read xml using XPATH in Java

I want to read XML data using XPath in java, so for the information I have gathered I am not able to parse xml according to my requirement,
I just want to take the value of bankId
this the example of the xml
I want to read XML data using XPath in java, so for the information I have gathered I am not able to parse xml according to my requirement,
I just want to take the value of 'bankId'
this part of the example of the xml
<?xml version="1.0" encoding="UTF-8"?>
<p:RawData xsi:type="p:RawData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ba="http://service.bni.co.id/bancslink" xmlns:bo="http://service.bni.co.id/core/bo" xmlns:core="http://service.bni.co.id/core" xmlns:mhp="http://service.bni.co.id/mhp" xmlns:mpnG2="http://service.bni.co.id/mhp/mpn_g2" xmlns:mpnG2_1="http://service.bni.co.id/bancslink/mpn_g2" xmlns:p="http://BP_MultiHostPayment">
<boList>
<name>McpRequest</name>
<bo xsi:type="bo:CommonBillPaymentReq">
<billerCode>0128</billerCode>
<regionCode>0001</regionCode>
<billerName>MPN G2 IDR</billerName>
<billingNum>820150629548121</billingNum>
<customerName>EVA RAJAGUKGUK SH. M.KN </customerName>
<paymentMethod>2</paymentMethod>
<accountNum>0373163437</accountNum>
<trxAmount>50000</trxAmount>
<naration>820150629548121</naration>
<invoiceNum>820150629548121</invoiceNum>
<billInvoiceNum1>INVNUM1</billInvoiceNum1>
<billAmount1>0</billAmount1>
<billInvoiceNum2>INVNUM2</billInvoiceNum2>
<billAmount2>0</billAmount2>
<billInvoiceNum3>INVNUM3</billInvoiceNum3>
<billAmount3>0</billAmount3>
<isDecAmount>false</isDecAmount>
<trxDecAmount>50000</trxDecAmount>
</bo>
</boList>
<boList>
<name>McpTellerHeader</name>
<bo xsi:type="core:TellerHeader">
<tellerId>00004</tellerId>
<branchCode>0997</branchCode>
<overrideFlag>I</overrideFlag>
</bo>
</boList>
<boList>
<name>HostRequest</name>
<bo xsi:type="mhp:Request">
<header>
<hostId>MPN_G2</hostId>
<channelId>ATM</channelId>
<branchId></branchId>
<terminalId></terminalId>
<locationId></locationId>
<transDateTime>2015-06-30T22:26:33</transDateTime>
<transId>20150630T222633N042462J0000001969R840SLEXI0</transId>
</header>
<content xsi:type="mpnG2:PaymentReq">
<bankId>520009000990</bankId>
<billingInfo1>013</billingInfo1>
<billingInfo2>03</billingInfo2>
<billingInfo3>409257</billingInfo3>
<branchCode>0997</branchCode>
<channelType>7010</channelType>
<currency>IDR</currency>
<gmt>2015-06-30T15:26:33.942</gmt>
<localDatetime>2015-06-30T22:26:33.943</localDatetime>
<settlementDate>0701</settlementDate>
<switcherCode>001</switcherCode>
<terminalId>S1HKWGA032</terminalId>
<terminalLocation>0997</terminalLocation>
<transactionId>013978</transactionId>
<amount>50000</amount>
<billerAccountNumber>3010194605</billerAccountNumber>
<customerName>EVA RAJAGUKGUK SH. M.KN </customerName>
<ntb>000000058111</ntb>
<paymentCode>820150629548121</paymentCode>
</content>
</bo>
</boList>
</p:RawData>
this is my java code
try {
FileInputStream file = new FileInputStream(new File("C:/Log/contoh.xml"));
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
System.out.println("hup hup");
String expression = "/p:RawData/boList/boList/boList/bo/content[#xsi:type='mpnG2:PaymentReq']/bankId";
System.out.println(expression);
String bankId = xPath.compile(expression).evaluate(xmlDocument);
System.out.println(bankId);
System.out.println("hup hup 2");
expression = "/p:RawData/boList/boList/boList/bo/content[#xsi:type='mpnG2:PaymentReq']/bankId";
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());
}
only this that appear when I run the code
hup hup
/p:RawData/boList/boList/boList/bo/content[#xsi:type='mpnG2:PaymentReq']/bankId
hup hup 2
any help will be pleasure :)
Try the following xpaths
//content[#xsi:type='mpnG2:PaymentReq']/bankId or
//content[#xsi:type='mpnG2:PaymentReq'][1]/bankId or
//bankId or
//bankId[1]
I've tested the xpaths for your xml in this online Xml Xpath tester
The XPath expression is wrong.
/p:RawData/boList/boList/boList/bo/content[#xsi:type='mpnG2:PaymentReq']/bankId
would select the element at:
<p:RawData>
<boList>
<boList>
<boList>
<bo>
<content xsi:type="mpnG2:PaymentReq" />
</bo>
</boList>
</boList>
</boList>
</RawData>
There is no such element in the XML.
You want
/p:RawData/boList[3]/bo/content[#xsi:type='mpnG2:PaymentReq']/bankId
To select the 3rd boList.

How to select all child nodes from a parent node from xml if there are many parents node with same name?

<?xml version="1.0" encoding="UTF-8"?>
<invoice>
<obs>
<ob>
<code>ABC</code>
</ob>
<ob>
<code>123</code>
</ob>
</obs>
</invoice>
<invoice>
<obs>
<ob>
<code>DEF</code>
</ob>
</obs>
</invoice>
</invoices>
Question:
I have that xml, which will come to me from external system ,it can have large number of invoice nodes and one invoice node can have large number of 'code' nodes. I want to read the code nodes of all 'invoice' nodes and save them in an array like this :
invoice[1].code[1]=ABC
invoice[1].code[2]=123
invoice[2].code[1]=DEF
How to do this using XPathExpression in JAVA. My code is below which is not working.
expr = xpath.compile("//invoices/invoice/obs/ob/code/text()");
result1=expr.evaluate(dc, XPathConstants.NODESET);
nodes =(NodeList)result1;
Please give some general solution in case of number of nodes are high.
It will give both as there are two invoices try to give id to your xml like
<invoices>
<invoice name="invoice1">
<obs>
<ob>
<code>ABC</code>
</ob>
</obs>
</invoice>
<invoice name="invoice2">
<obs>
<ob>
<code>DEF</code>
</ob>
</obs>
</invoice>
</invoices>
then
expr = xpath.compile("//invoices[#name='invoice1']/invoice/obs/ob/code/text()");
you could try this xpath:
//invoices/invoice[descendant::code[.='ABC']]/obs/ob/code
There are 2 nodes where your xpath passes. You can try this.
String xml = "<invoices><invoice><obs><ob><code>ABC</code></ob><ob><code>111</code></ob></obs></invoice><invoice><obs><ob><code>DEF</code></ob></obs></invoice></invoices>";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder =factory.newDocumentBuilder();
Document document = builder.parse(new InputSource(new StringReader(xml)));
XPathFactory xpathFactory = XPathFactory.newInstance();
Map<String,List<String>> invoiceCodeMap = new LinkedHashMap<>();
XPathExpression invoiceXpathExp = xpathFactory.newXPath().compile("//invoices/invoice");
NodeList invoiceNodes = (NodeList) invoiceXpathExp.evaluate(document, XPathConstants.NODESET);
//Iterate Invoice nodes
for(int invoiceIndex=0;invoiceIndex<invoiceNodes.getLength();invoiceIndex++){
String invoiceID = "invoice"+(invoiceIndex+1);
List<String> codeList = new ArrayList<>();
XPathExpression codeXpathExp = xpathFactory.newXPath().compile("obs/ob/code/text()");
NodeList codeNodes = (NodeList) codeXpathExp.evaluate(invoiceNodes.item(invoiceIndex), XPathConstants.NODESET);
for(int codeIndex=0;codeIndex<codeNodes.getLength();codeIndex++){
Node code = codeNodes.item(codeIndex);
codeList.add(code.getTextContent());
}
invoiceCodeMap.put(invoiceID, codeList);
}
System.out.println(invoiceCodeMap);

Getting the value of an attribute in Java from a XML using XPath

I'm currently using XPath to get some information from a podcast feed using Java and XPath. I'm trying to read the attribute of a node:
<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/" xmlns:atom="http://www.w3.org/2005/Atom/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0">
<channel>
[....]
<itunes:image href="http://icebox.5by5.tv/images/broadcasts/14/cover.jpg" />
[...]
I want to get the value of the href attribute in <itunes:image>. Currently, I'm using the following code:
private static String IMAGE_XPATH = "//channel/itunes:image/#href";
String imageUrl = xpath.compile(IMAGE_XPATH).evaluate(doc, XPathConstants.STRING).toString();
The result of imageUrl is null. What happens in the code? Do I have an error in the XPath code, or in the Java code?
Thanks! :)
Disable namespace awarness:
DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
xmlFact.setNamespaceAware(false);
Your xpath expression should look like this now:
"//channel/image/#href"
If you need to use it as namespace aware, just implement your own NameSpaceContext, should look like this:
NamespaceContext ctx = new ItunesNamespaceContext();
XPathFactory xpathFact = XPathFactory.newInstance();
XPath xpath = xpathFact.newXPath();
xpath.setNamespaceContext(ctx);
String IMAGE_XPATH = "//channel/itunes:image/#href";
String imageUrl = path.compile(IMAGE_XPATH).evaluate(doc,XPathConstants.STRING).toString();
EDIT: Here is a test code that proves my point:
String a ="<?xml version=\"1.0\" encoding=\"UTF-8\"?><rss xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:sy=\"http://purl.org/rss/1.0/modules/syndication/\" xmlns:admin=\"http://webns.net/mvcb/\" xmlns:atom=\"http://www.w3.org/2005/Atom/\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\" xmlns:itunes=\"http://www.itunes.com/dtds/podcast-1.0.dtd\" version=\"2.0\"><channel><itunes:image href=\"http://icebox.5by5.tv/images/broadcasts/14/cover.jpg\" /></channel></rss>";
DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
xmlFact.setNamespaceAware(false);
DocumentBuilder builder = xmlFact.newDocumentBuilder();
XPathFactory xpathFactory = XPathFactory.newInstance();
String expr = "//channel/image/#href";
XPath xpath = xpathFactory.newXPath();
Document doc = builder.parse(new InputSource(new StringReader(a)));
String imageUrl = (String) xpath.compile(expr).evaluate(doc ,XPathConstants.STRING);
System.out.println(imageUrl);
The output is:
http://icebox.5by5.tv/images/broadcasts/14/cover.jpg
The XPath should include the root element, so rss/channel/itunes:image/#href.
Alternatively, you could start the xpath with a // so that all levels are searched for the xpath (//channel/itunes:image/#href) but if the root will always be the same it is more efficient to use the first option.

how to get a node value in Xpath - Java

I've got a section of XML that looks like this:
<entry>
<id>tag:example.com,2005:Release/343597</id>
<published>2012-04-10T11:29:19Z</published>
<updated>2012-04-10T12:04:41Z</updated>
<link type="text/html" href="http://example.com/projects/example1" rel="alternate"/>
<title>example1</title>
</entry>
I need to grab the link http://example.com/projects/example1 from this block. I'm not sure how to do this. To get the title of the project I use this code:
String title1 = children.item(9).getFirstChild().getNodeValue();
where children is the getChildNodes() object for the <entry> </entry> block. But I keep getting NullPointerExceptions when I try to get the node value for the <link> node in a similar way. I see that the XML code is different for the <link> node, and I'm not sure what it's value is.... Please advise!
The xpath expression to get that node is
//entry/link/#href
In java you can write
Document doc = ... // your XML document
XPathExpression xp = XPathFactory.newInstance().newXPath().compile("//entry/link/#href");
String href = xp.evaluate(doc);
Then if you need to get the link value of the entry with a specific id you can change the xpath expression to
//entry[id='tag:example.com,2005:Release/343597']/link/#href
Finally if you want to get all the links in the documents, if the document has many entry elements you can write
Document doc = ... // your XML document
XPathExpression xp = XPathFactory.newInstance().newXPath().compile("//entry/link/#href");
NodeList links = (NodeList) xp.evaluate(doc, XPathConstants.NODESET);
// and iterate on links
Here is the complete code:
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("//entry/link/#href");
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