An XPath expression in Java for getting xml elements - java

I want to get nodes from an api which contains xml elements.
https://www.w3schools.com/xml/cd_catalog.xml Here is the link for the api.
So my Java code is like this:
package in.automationtesting.neh;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Test1 {
public static final String GET_API_URL = "https://www.w3schools.com/xml/cd_catalog.xml";
public static void main(String[] args) throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.GET()
.header("accept", "application/xml")
.uri(URI.create(GET_API_URL))
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
XPathFactory xpathfactory = XPathFactory.newInstance();
XPath xpath = xpathfactory.newXPath();
try {
Reader reader = new StringReader(response.body());
InputSource inputSource = new InputSource(reader);
XPath xpath1 = XPathFactory.newInstance().newXPath();
System.out.println(xpath1.evaluate("//CATALOG/CD", inputSource));
} catch (XPathExpressionException e) {
e.printStackTrace();
}
}
}
The output on the console should be like this:
<CATALOG>
<CD>
<TITLE>1999 Grammy Nominees</TITLE>
<ARTIST>Many</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Grammy</COMPANY>
<PRICE>10.20</PRICE>
<YEAR>1999</YEAR>
</CD>
<CD>
<TITLE>Big Willie style</TITLE>
<ARTIST>Will Smith</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1997</YEAR>
</CD>
</CATALOG>
With the xpath expression i want to get the cd's which are released from 1995 and later ,plus they should be only from USA. And when i only match the root in the xpath expression which is CATALOG it shows all the elements which is good, but when i add cd next to it, on the console it only shows one album and not all of them, idk why i tried something like this in the expression and other varieties of it but no luck "//CATALOG/CD[#year>1995 and country='USA']

You have to use a NodeList with XPathConstants.NODESET
Your expression is /CATALOG/CD[COUNTRY='USA' and YEAR>=1985]
(The "#" is for attributes)
The syntax is:
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class Test1 {
public static final String GET_API_URL = "https://www.w3schools.com/xml/cd_catalog.xml";
public static void main(String[] args) throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().GET().header("accept", "application/xml").uri(URI.create(GET_API_URL)).build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
try {
Reader reader = new StringReader(response.body());
InputSource inputSource = new InputSource(reader);
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile("/CATALOG/CD[COUNTRY='USA' and YEAR>=1985]");
NodeList list = (NodeList)expr.evaluate(inputSource, XPathConstants.NODESET);
for (int i = 0; i < list.getLength(); i++) {
Node node = list.item(i);
System.out.println(node.getTextContent());
}
}
catch (XPathExpressionException e) {
e.printStackTrace();
}
}
}
That gives:
Empire Burlesque
Bob Dylan
USA
Columbia
10.90
1985
When a man loves a woman
Percy Sledge
USA
Atlantic
8.70
1987
1999 Grammy Nominees
Many
USA
Grammy
10.20
1999
Big Willie style
Will Smith
USA
Columbia
9.90
1997
Unchain my heart
Joe Cocker
USA
EMI
8.20
1987

This other solution uses a Transformer to format the output.
I found this solution here and here.
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
public class Test1 {
public static final String GET_API_URL = "https://www.w3schools.com/xml/cd_catalog.xml";
public static void main(String[] args) throws IOException, InterruptedException {
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder().GET().header("accept", "application/xml").uri(URI.create(GET_API_URL)).build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
try {
Reader reader = new StringReader(response.body());
InputSource inputSource = new InputSource(reader);
XPath xpath = XPathFactory.newInstance().newXPath();
XPathExpression expr = xpath.compile("/CATALOG/CD[COUNTRY='USA' and YEAR>=1985]");
NodeList list = (NodeList)expr.evaluate(inputSource, XPathConstants.NODESET);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
for (int i = 0; i < list.getLength(); i++) {
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(list.item(i)), new StreamResult(writer));
System.out.println(writer.toString());
}
}
catch (XPathExpressionException | TransformerException e) {
e.printStackTrace();
}
}
}
The result is now:
<CD>
<TITLE>Empire Burlesque</TITLE>
<ARTIST>Bob Dylan</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>10.90</PRICE>
<YEAR>1985</YEAR>
</CD>
<CD>
<TITLE>When a man loves a woman</TITLE>
<ARTIST>Percy Sledge</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Atlantic</COMPANY>
<PRICE>8.70</PRICE>
<YEAR>1987</YEAR>
</CD>
<CD>
<TITLE>1999 Grammy Nominees</TITLE>
<ARTIST>Many</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Grammy</COMPANY>
<PRICE>10.20</PRICE>
<YEAR>1999</YEAR>
</CD>
<CD>
<TITLE>Big Willie style</TITLE>
<ARTIST>Will Smith</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>Columbia</COMPANY>
<PRICE>9.90</PRICE>
<YEAR>1997</YEAR>
</CD>
<CD>
<TITLE>Unchain my heart</TITLE>
<ARTIST>Joe Cocker</ARTIST>
<COUNTRY>USA</COUNTRY>
<COMPANY>EMI</COMPANY>
<PRICE>8.20</PRICE>
<YEAR>1987</YEAR>
</CD>

Related

How to disable newline and indenting in DOM Transformer?

I am parsing an XML document and serializing it back. I want to preserve the original indentation and newlines as much as possible. I do not wish to pretty print the DOM.
Consider the code below where the original document has a single new line before and after the <div> tag and no indentation.
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
import org.xml.sax.InputSource;
import java.io.StringReader;
public class Test {
public static void main(String args[]) throws Exception {
String xmlIn = "<html>\n<div>Hello World!</div>\n</html>";
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = documentBuilder.parse(new InputSource(new StringReader(xmlIn)));
TransformerFactory transfac = TransformerFactory.newInstance();
Transformer domTransformer = transfac.newTransformer();
domTransformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
domTransformer.setOutputProperty(OutputKeys.INDENT, "no");
StreamResult result = new StreamResult(System.out);
DOMSource source = new DOMSource(doc);
domTransformer.transform(source, result);
}
}
The expectation is to see this:
<html>
<div>Hello World!</div>
</html>
But, Java 8 is printing:
<html>
<div>Hello World!</div>
</html>
Java 11 is printing:
<html>
<div>Hello World!</div>
</html>
As you can see, they are both adding an extra new line. Java 11 has also added indentation.
How can I prevent adding extra new lines and indentations?

Cannot get first child of Xml Node

My problem is in getting the first child of an XML node using the getFirstChild().
My xml is very basic, as follows :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<network name="beep">
<layers number="3">
<layer index="0" lenght="3">
...
</layer>
<layer index="1" lenght="3">
...
</layer>
....
</layers>
</network>
Java-code
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.StringReader;
import org.xml.sax.InputSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
try {
DocumentBuilderFactory DBF = DocumentBuilderFactory.newInstance();
DocumentBuilder DB = DBF.newDocumentBuilder();
Document doc = DB.parse(new InputSource( new StringReader(Xml)));
doc.getDocumentElement().normalize();
Element root = doc.getDocumentElement();
NodeList Nodes =root.getElementsByTagName("network");
Node Layers = Nodes.item(0).getFirstChild();
}
catch (Exception ex)
{
}
as you can see there is an element which is a child of "network" and it is a "layer".
I can successfully access to the network, getting the list of nodes, which is basically one node, but as soon as I try to get the first child of the first (and only) node with :
Node Layers = Nodes.item(0).getFirstChild();
I get an exception, and, even funnier, the exception is null.
Where's the problem?
Please try below code(both Files):
1) XML File:
_________
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<network name="beep">
<layers number="3">
<layer index="0" lenght="3">Hare</layer>
<layer index="1" lenght="3">Rama</layer>
<layer index="0" lenght="3">Hare</layer>
<layer index="1" lenght="3">Krishna</layer>
</layers>
</network>
**************************************************************
2) Java File:
__________
import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
public class XMLDemo {
public static void main(String...lsdfs) {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
try {
InputStream inputStream = XMLDemo.class.getClassLoader().getResourceAsStream("dataFilePackage/XmlData.xml");
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(inputStream);
NodeList nodeList = document.getElementsByTagName("network");
System.out.println(nodeList.item(0).getTextContent());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
I modified your xml to :
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<network name="beep">
<layers number="3">
<layer index="0" lenght="3">Vishwa</layer>
<layer index="1" lenght="3">Ratna</layer>
</layers>
</network>
Java code:
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class Main {
public static void main(String[] args) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
InputStream inputStream = Main.class
.getClassLoader().getResourceAsStream("resources/nodes.xml");
Document doc = builder.parse(inputStream);
NodeList nodes = doc.getElementsByTagName("network");
System.out.println(nodes.item(0).getTextContent());
} catch (FileNotFoundException | ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
O/P
Vishwa
Ratna

get all node from xml having specific attriute value java

<main-project name="" version="1.0.2">
<data name="data">
<tag>
<link-to object="processor"/>
</tag>
</data>
<output name="output">
<tag>
<link-to object="processor"/>
</tag>
</output>
<processor name ="processor">
<tag>
<link-to object="data"/>
</tag>
</processor>
</main-project>
I wants to get all nodes having having attribute object = processor ,i have tried using
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList linkageNodesEpf = (NodeList) xPath.compile("//link-to[#object = 'processor']").evaluate(Doc, XPathConstants.NODESET);
This query gives empty list but when i replace link-to to link above query works fine and gives correct result,So i think may be dash(-) is creating the problem.
please help me to solve this problem
Well, that code:
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
public class SimpleClass2 {
public static void main(String[] args) throws InterruptedException, XPathExpressionException, ParserConfigurationException, IOException, SAXException {
String str = "<main-project name=\"\" version=\"1.0.2\">\n" +
"<data name=\"data\">\n" +
"<tag>\n" +
"<link-to object=\"processor\"/>\n" +
"</tag>\n" +
"</data>\n" +
"<output name=\"output\">\n" +
"<tag>\n" +
"<link-to object=\"processor\"/>\n" +
"</tag>\n" +
"</output>\n" +
"<processor name =\"processor\">\n" +
"<tag>\n" +
"<link-to object=\"data\"/>\n" +
"</tag>\n" +
"</processor>\n" +
"</main-project>";
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document xmlDoc = builder.parse(new ByteArrayInputStream(str.getBytes()));
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList linkageNodesEpf = (NodeList) xPath.compile("//link-to[#object = 'processor']").evaluate(xmlDoc, XPathConstants.NODESET);
for (int i = 0; i < linkageNodesEpf.getLength(); i++) {
System.out.println(linkageNodesEpf.item(i));
}
}
}
Produces sush results on my machine(oracle jdk8_45):
[link-to: null]
[link-to: null]
Could you try copying it, what results does it produce?

Parsing using Dom produces type mismatch

Given the following code , under Eclipse , I get a type mismatch error :
package xmlInterface;
import javax.swing.text.*;
import org.w3c.dom.*;
import org.w3c.dom.Document;
import gameManage.round;
import java.io.File;
import javax.lang.model.element.Element;
import javax.swing.text.Segment;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import com.sun.org.apache.bcel.internal.classfile.Method;
public void writeToXml(round[] games) throws ParserConfigurationException
{
int i;
// build a doucument by the parser
DocumentBuilderFactory document = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = document.newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("GameOut");
...
...
...
}
I get the following error in Eclipse :
Type mismatch: cannot convert from org.w3c.dom.Element to javax.lang.model.element.Element
Can anyone please explain how can I fix this ?
Thank you
Jason
I think you've mistaken an import. Not
import javax.lang.model.element.Element;
but
import org.w3c.dom.Element;
Don't use import with * like
org.w3c.dom.*
otherwise you'd be likely to get some "hiding" error, since the last "Element" import you've coded (javax.lang.model.element.Element) will hide the org.w3c.dom.Element included in the import org.w3c.dom.* line.

How can I do to find in xml with bitwise-and with xpath and java?

I have this sample xml.
Each row has an id field, it has values as bits.
And I want to find in this file with bitwise-and operator but I don't know if this is possible.
I read about the operator '&' in javascript or comand BITAND in Oracle but nothing in xml o xpath.
This is the example code in java and xpath:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class Util implements java.io.Serializable {
static public String filter_xpath_bitand (int var_tipo)
NodeList nodeList = null;
Element element = null;
try {
XPath xpath = XPathFactory.newInstance().newXPath();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(new File(fileXML));
nodeList = (NodeList)xpath.evaluate("/test/row[(id & \""+ var_tipo +"\") > 1]", document.getDocumentElement(), XPathConstants.NODESET);
} catch (Exception e) {
System.out.println("*** filterXML --> exception: " + e.toString());
}
}
}
From looking at the XPATH reference there is no such thing as bitwise operations.
You could work around that though by making use of existing operations (mod etc).
See here for a related question.
EDIT:
Sample xml:
<?xml version="1.0" encoding="UTF-8"?>
<test>
<row>
<id>32</id>
<titulo>yellow</titulo>
</row>
<row>
<id>16</id>
<titulo>green</titulo>
</row>
<row>
<id>8</id>
<titulo>red</titulo>
</row>
<row>
<id>1</id>
<titulo>blue</titulo>
</row>
<row>
<id>2</id>
<titulo>white</titulo>
</row>
<row>
<id>4</id>
<titulo>black</titulo>
</row>
</test>
Java code:
import java.io.File;
import java.util.HashSet;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
public class BitWiseXPathTest {
public static void main(String[] args) {
Set<String> selectedColors = new HashSet<String>();
int var_tipo = 33;
try {
XPath xpath = XPathFactory.newInstance().newXPath();
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
String fileXML = "bitwise.xml";
Document document = builder.parse(new File(fileXML));
String evalStr = "/test/row/id";
NodeList nodeList = (NodeList)xpath.evaluate(evalStr, document.getDocumentElement(), XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
Node aNode = nodeList.item(i);
if( (Integer.parseInt(aNode.getTextContent()) & var_tipo) > 0) {
//System.out.println("color: "+aNode.getNextSibling().getNextSibling().getTextContent());
selectedColors.add(aNode.getNextSibling().getNextSibling().getTextContent());
}
}
} catch (Exception e) {
System.out.println("*** filterXML --> exception: " + e.toString());
}
System.out.println(selectedColors);
}
}
Again, XPATH doesn't seem to have a bitwise operation. You could move the operation outside of XPATH and do it in Java as a workaround.

Categories