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
Related
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>
This is my XML file:
<Root>
<Id>1</Id>
<Title>My title</Title>
<More>
<Extension>Ex</Extension>
<Extra>Extra info</Extra>
<Comments>
<Comment date="2018-11-26T06:00:00+02:00">Hey, this is my comment</Comment>
<Comment date="2017-11-26T06:00:00+02:00">Hey, this is my comment</Comment>
<Comment date="2016-11-26T06:00:00+02:00">Hey, this is my comment</Comment>
<Comment date="2011-11-26T06:00:00+02:00">Hey, this is my comment</Comment>
</Comments>
</More>
</Root>
I am only interested in <Comment> data.
My current approach is using JaxB unmarshalling and having classes Root.java, More.java, Comments.java which contains class Comment.java. So it's kinda messy.
I have no problem doing it this way, but I would like to know if there is any method that let's you go straight for the <Comment> data and having only 1 class Comment.java for it?
If you only want to get all the comment tags from the XML file, you may try out following approach,
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class ReadComments {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
File xml = new File("D:/data.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbFactory.newDocumentBuilder();
Document doc = docBuilder.parse(xml);
doc.getDocumentElement().normalize();
NodeList nodeList = doc.getElementsByTagName("Comment");
for (int i= 0; i< nodeList.getLength(); i++) {
Node node = nodeList.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
Element element = (Element) node;
System.out.printf("Comment : %s | Date : %s\n", node.getTextContent(), element.getAttribute("date"));
}
}
}
}
Output :
Comment : Hey, this is my comment | Date : 2018-11-26T06:00:00+02:00
Comment : Hey, this is my comment | Date : 2017-11-26T06:00:00+02:00
Comment : Hey, this is my comment | Date : 2016-11-26T06:00:00+02:00
Comment : Hey, this is my comment | Date : 2011-11-26T06:00:00+02:00
Note that this is just an example to explain about getting details of specific tags, you will have to modify this code as per for your need.
I made a minimal example to reproduce the problem. This is the transformation (mini.xsl):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<foo>
<xsl:copy-of select="."/>
</foo>
</xsl:template>
</xsl:stylesheet>
and this is the input (mini.xml):
<?xml version="1.0" encoding="utf-8"?>
<bar xmlns:x="baz">
<x:baz/>
</bar>
When I apply the transformation with
xsltproc mini.xsl mini.xml
the result looks as expected:
<?xml version="1.0"?>
<foo>
<bar xmlns:x="baz">
<x:baz/>
</bar>
</foo>
However, when I run the transformation with the following Java program,
import java.io.FileInputStream;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class Program
{
public static void main(String[] args)
{
try
{
Source transform = new StreamSource(new FileInputStream(args[0]));
Templates templates = TransformerFactory.newInstance().newTemplates(transform);
Document input = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new FileInputStream(args[1]));
Result result = new StreamResult(System.out);
templates.newTransformer().transform(new DOMSource(input), result);
}
catch (TransformerFactoryConfigurationError | ParserConfigurationException | SAXException | IOException | TransformerException e)
{
e.printStackTrace();
}
}
}
the result looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar xmlns:x="baz">
<baz/>
</bar>
</foo>
(notice that the x: prefix in front of baz is missing.)
Why is that?
And what can I do about it (to preserve the namespace prefix)?
For what I can only assume are historical reasons, DocumentBuilderFactory is non-namespace-aware by default. You need to explicitly switch on namespaces before you do newDocumentBuilder().
It would also be better to use the parse method that takes a File directly rather than creating your own FileInputStream (which your code is not closing once the parse is finished), and likewise with the StreamSource from which the Transformer is built.
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document input = dbf.newDocumentBuilder().parse(new File(args[1]));
This question already has answers here:
Remove 'standalone="yes"' from generated XML
(13 answers)
Closed 9 years ago.
I wrote code for tests - it creates simple XML document. My problem is that created document contains unneeded data in first node . Is any way to delete or modify this node <?xml version="1.0" encoding="UTF-8" standalone="no"?> ?
import java.io.ByteArrayOutputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
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 org.w3c.dom.Document;
import org.w3c.dom.Element;
public class MyTestClass {
public static void main(String argv[]) {
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
// root elements
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("company");
doc.appendChild(rootElement);
// staff elements
Element staff = doc.createElement("Staff");
rootElement.appendChild(staff);
// firstname elements
Element firstname = doc.createElement("firstname");
firstname.appendChild(doc.createTextNode("yong"));
staff.appendChild(firstname);
// lastname elements
Element lastname = doc.createElement("lastname");
lastname.appendChild(doc.createTextNode("mook kim"));
staff.appendChild(lastname);
// nickname elements
Element nickname = doc.createElement("nickname");
nickname.appendChild(doc.createTextNode("mkyong"));
staff.appendChild(nickname);
// salary elements
Element salary = doc.createElement("salary");
salary.appendChild(doc.createTextNode("100000"));
staff.appendChild(salary);
Transformer t = TransformerFactory.newInstance().newTransformer();
ByteArrayOutputStream s = new ByteArrayOutputStream();
t.setOutputProperty(OutputKeys.INDENT, "yes");
t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
t.transform(new DOMSource(doc),new StreamResult(s));
System.out.println(new String(s.toByteArray()));
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (TransformerException tfe) {
tfe.printStackTrace();
}
}
}
It returns:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<company>
<Staff>
<firstname>yong</firstname>
<lastname>mook kim</lastname>
<nickname>mkyong</nickname>
<salary>100000</salary>
</Staff>
</company>
Is any way to delete or modify this node <?xml version="1.0" encoding="UTF-8" standalone="no"?> ?
You can add the following to your Transformer
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
see here for details
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.