I am trying to read from xml file but I get a null pointer exception.
this is the xml file:
<war>
<missileLaunchers>
<launcher id="L101" isHidden="false">
<missile id="M1" destination="Sderot" launchTime="2" flyTime="12" damage="1500"/>
<missile id="M2" destination="Beer-Sheva" launchTime="5" flyTime="7" damage="2000"/>
</launcher>
<launcher id="L102" isHidden="true">
<missile id="M3" destination="Ofakim" launchTime="4" flyTime="3" damage="5000"/>
<missile id="M4" destination="Beer-Sheva" launchTime="9" flyTime="7" damage="1000"/>
</launcher>
</missileLaunchers>
<missileDestructors >
<destructor id="D201">
<destructdMissile id="M1" destructAfterLaunch="4"/>
<destructdMissile id="M3" destructAfterLaunch="7" />
<destructdMissile id="M4" destructAfterLaunch="2"/>
</destructor>
<destructor id="D202">
<destructdMissile id="M2" destructAfterLaunch="3"/>
</destructor>
</missileDestructors>
<missileLauncherDestructors >
<destructor type="plane" >
<destructedLanucher id="L101" destructTime="4"/>
</destructor>
<destructor type="ship">
<destructedLanucher id="L102" destructTime="8" />
<destructedLanucher id="L102" destructTime="12"/>
</destructor>
</missileLauncherDestructors>
</war>
and this is the code:
public class XmlReader
{
File fXmlFile=null;
DocumentBuilderFactory dbFactory=null;
DocumentBuilder dBuilder=null;
Document doc=null;
public XmlReader(String filePath) throws ClassNotFoundException
{
if(filePath!=null)
{
this.fXmlFile = new File(filePath);
dbFactory = DocumentBuilderFactory.newInstance();
try {
dBuilder = dbFactory.newDocumentBuilder();
} catch (ParserConfigurationException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
doc = dBuilder.parse(fXmlFile);
doc.getDocumentElement().normalize();
} catch (SAXException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else System.out.println("Xml file not found");
}
//gets value by tag name
private static String getTagValue(String tag, Element element) {
if(element.hasChildNodes())
{
NodeList nodeList = element.getElementsByTagName(tag).item(0).getChildNodes();
Node node = (Node) nodeList.item(0);
if(node==null)
return null;
return node.getNodeValue();
}
else return element.getNodeValue();
}
//launcher
public List<Launcher> readLauncher() throws Exception
{
List<Launcher> launcherList = new ArrayList<Launcher>();
try
{
NodeList nList = doc.getElementsByTagName("launcher");
for(int i=0;i<nList.getLength();i++)
{launcherList.add(getLauncher(nList.item(i)));}
}
catch (Exception e)
{
e.printStackTrace();
}
return launcherList;
}
//builds the object
private static Launcher getLauncher(Node node)
{
//XMLReaderDOM domReader = new XMLReaderDOM();
Launcher launcher = new Launcher();
if (node.getNodeType() == Node.ELEMENT_NODE)
{
Element element = (Element) node;
// launcher.setIsHidden(Boolean.parseBoolean(getTagValue("isHidden", element)));
// launcher.setId(getTagValue("id", element));
System.out.println("id = "+getTagValue("id", element));
System.out.println("ishidden = "+getTagValue("isHidden", element));
}
return launcher;
}
}
And this is the stack trace:
java.lang.NullPointerException
at XmlReader.getTagValue(XmlReader.java:56)
at XmlReader.getLauncher(XmlReader.java:96)
at XmlReader.readLauncher(XmlReader.java:78)
at Program.main(Program.java:27)
I can not change the format of the xml file.
It seems to fail when it tries to get the actual value of the node's fields or so I assume.
Though I don;t understand the reason...when I check the size of the node list it turns fine it does give me 2.
The problem is below line:
System.out.println("id = " + getTagValue("id", element));
where getTagValue("id", element) is calling
NodeList nodeList = element.getElementsByTagName(tag).item(0).getChildNodes();
Here element.getElementsByTagName("id") will return null
It should be get from attribute
// gets value by tag name
private static String getTagValue(String tag, Element element) {
return element.getAttributeNode(tag).getValue();
}
You are calling getElementsByTagName() in getTagValues, however you are trying to retrieve attributes of the tag. You may need to call getAttribute() instead. For Example:
element.getAttribute(attributeName)
where attributeName is "id" or "isHidden". This will return the value as a String and can be returned directly with no further processing.
Related
I have a use case where my XML is like this
<IR>
<name>abc</name>
<Level></Level>
</IR>
<IR>
<name>xyz</name>
<Level>LVL00006</Level>
</IR>
I am using below code to extract information of level.
public class TestUseCases {
public static void main(String[] args) {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
} catch (ParserConfigurationException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
Document document;
try {
document = factory.newDocumentBuilder()
.parse(new InputSource(new StringReader(xml)));
String xpathExpression = "";
Map<String, List<String>> iRValues = new LinkedHashMap<String, List<String>>();
xpathExpression = "(/IR/Level/text())";
iRValues.put("REQLVL", evaluateXPath(document, xpathExpression));
System.out.println(iRValues);
} catch (SupportException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException | IOException | ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static List<String> evaluateXPath(Document document, String xpathExpression) throws SupportException {
// Create XPathFactory object
XPathFactory xpathFactory = XPathFactory.newInstance();
// Create XPath object
XPath xpath = xpathFactory.newXPath();
List<String> values = new ArrayList<>();
try {
// Create XPathExpression object
XPathExpression expr = xpath.compile(xpathExpression);
// Evaluate expression result on XML document
NodeList nodes = (NodeList) expr.evaluate(document, XPathConstants.NODESET);
System.out.println(nodes.getLength());
for (int i = 0; i < nodes.getLength(); i++) {
String item = nodes.item(i).getNodeValue();
System.out.println(item);
if (item.trim().isEmpty()) {
values.add(SupportConstants.EMPTY_SPACE);
} else {
values.add(nodes.item(i).getNodeValue());
}
}
} catch (XPathExpressionException e) {
throw new SupportException(SupportExceptionMessage.ERROR_IN_READING_RESPONSE_FROM_CM);
}
return values;
}
}
OUTPUT:
1
LVL00006
{REQLVL=[LVL00006]}
The problem is because first level tag is empty, I get a list which has only one element and I am not able to know whether the element is of abc or xyz. Is there a way so that I can put space if the tag is empty?
I am expecting list as [" ", LVL00006].
try {
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc = builder.parse("15122021.xml");
NodeList currencyList= doc.getElementsByTagName("Currency");
for(int i=0;i<currencyList.getLength();i++){
Node p = currencyList.item(i);
if(p.getNodeType()==Node.ELEMENT_NODE){
Element mainTag = (Element) p;
NodeList currencySellPriceList= mainTag.getElementsByTagName("ForexSelling");
NodeList currencyBuyPriceList = mainTag.getElementsByTagName("ForexBuying");
NodeList currencyNameList2= mainTag.getElementsByTagName("CurrencyName");
for(int j=0;j<currencyNameList2.getLength();j++){
Node c=currencyNameList2.item(j);
Node cbp=currencyBuyPriceList.item(j);
Node csp=currencySellPriceList.item(j);
if(c.getNodeType()==Node.ELEMENT_NODE && cbp.getNodeType()==Node.ELEMENT_NODE && csp.getNodeType()==Node.ELEMENT_NODE){
System.out.println("Currency name: "+c.getTextContent());
System.out.println("Buy price: "+cbp.getTextContent());
System.out.println("Sell price: "+csp.getTextContent());
}
}
}
}
} catch (ParserConfigurationException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
} catch (SAXException e) {
System.out.println(e.getMessage());
}
I am trying to parse XML file like this in main method and it works.But when i try to take this code block to another method like this
public class XMLScraperBuilder {
public NodeList getBuyPrices() throws IOException, SAXException, ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
NodeList currencySellPriceList=null;
DocumentBuilder builder=factory.newDocumentBuilder();
Document doc = builder.parse("15122021.xml");
NodeList currencyList= doc.getElementsByTagName("Currency");
for(int i=0;i<currencyList.getLength();i++){
Node currency = currencyList.item(i);
if(currency.getNodeType()==Node.ELEMENT_NODE){
Element mainTag = (Element) currency;
currencySellPriceList= mainTag.getElementsByTagName("ForexSelling");
for(int j=0;j<currencySellPriceList.getLength();j++){
Node c = currencySellPriceList.item(j);
}
}}
return currencySellPriceList;
}}
It returns nothing when i try to print the NodeList with a for loop in my main method(after creating an object from XMLScraperBuilder).Any ideas?
While creating a new node and appending into existing XML-document using below code snippet
the expression is XPath like "rootNode/parentNode1/parentNode2/childNode"
private static Node createParentNode(Document xmlDocument, String expression, String parentRootXPath)
throws XPathExpressionException {
final String childXPath = (expression.replace(parentRootXPath, "")).replaceFirst("/", "");
final StringBuilder parentPathBuilder = new StringBuilder(parentRootXPath);
Arrays.stream(childXPath.split("/")).forEach(childNodeName -> {
try {
Node parentNode = getNode(xmlDocument, parentPathBuilder.toString());
Node childNode = xmlDocument.createElement(childNodeName);
parentPathBuilder.append("/").append(childNodeName);
parentNode.appendChild(childNode);
} catch (XPathExpressionException e) {
LOGGER.error("Unable to create Node {}", parentPathBuilder.toString());
}
});
return getNode(xmlDocument, expression);
}
private static Node getNode(Document xmlDocument, String expression) throws XPathExpressionException {
return (Node) X_PATH.compile(expression).evaluate(xmlDocument, XPathConstants.NODE);
}
I am able to append the node but while parsing extra end node tag is generating
<DOCUMENT_SETS>
<DOCUMENT_SPECIFIC_DATA_SET>
<node1>value1</node1>
<new_Node1>value1</new_Node1>
<new_Node2>value1</new_Node2>
</DOCUMENT_SPECIFIC_DATA_SET>
</DOCUMENT_SETS>
<DOCUMENT_SPECIFIC_DATA_SET />
<DOCUMENT_SPECIFIC_DATA_SET />
Input
<DOCUMENT_SETS>
<DOCUMENT_SPECIFIC_DATA_SET>
<node1>value1</node1>
</DOCUMENT_SPECIFIC_DATA_SET>
</DOCUMENT_SETS>
Expected output
<DOCUMENT_SETS>
<DOCUMENT_SPECIFIC_DATA_SET>
<node1>value1</node1>
<new_Node1>value1</new_Node1>
<new_Node2>value1</new_Node2>
</DOCUMENT_SPECIFIC_DATA_SET>
</DOCUMENT_SETS>
Duplicate end tags are get inserted due to creating a child node without checking is the node already exists or not.
private static Node createParentNode(Document xmlDocument, String expression, String parentRootXPath)
throws XPathExpressionException {
final String childXPath = (expression.replace(parentRootXPath, "")).replaceFirst("/", "");
final StringBuilder parentPathBuilder = new StringBuilder(parentRootXPath);
Arrays.stream(childXPath.split("/")).forEach(childNodeName -> {
try {
Node parentNode = getNode(xmlDocument, parentPathBuilder.toString());
parentPathBuilder.append("/").append(childNodeName);
Node childNode = getNode(xmlDocument, parentPathBuilder.toString());
if(Objects.nonNull(childNode)){
childNode = xmlDocument.createElement(childNodeName);
parentNode.appendChild(childNode);
}
} catch (XPathExpressionException e) {
LOGGER.error("Unable to create Node {}", parentPathBuilder.toString());
}
});
return getNode(xmlDocument, expression);
}
I am making some changes to an embedded XML file in my Java application. I have some fields, a LOAD button and a SAVE button. After clicking the save button I can see the XML file updating, but after clicking the load button the old values are being loaded to the fields.
Here is my code:
public class MyLoad_SaveSampleProject {
public String field1 = "";
public String field2 = "";
public void loadSampleProject() {
InputStream file = MyLoad_SaveSampleProject.class.getResourceAsStream("/main/resources/otherClasses/projects/SampleProject.xml");
try {
DocumentBuilderFactory DocBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder DocBuilder = DocBuilderFactory.newDocumentBuilder();
Document Doc = DocBuilder.parse(file);
NodeList list = Doc.getElementsByTagName("*"); //create a list with the elements of the xml file
for (int i=0; i<list.getLength(); i++) {
Element element = (Element)list.item(i);
if (element.getNodeName().equals("field1")) {
field1 = element.getChildNodes().item(0).getNodeValue().toString();
} else if (element.getNodeName().equals("field2")) {
field2 = element.getChildNodes().item(0).getNodeValue().toString();
}
}
} catch (Exception e) {
System.out.println(e);
}
}
public void saveSampleProject(String field1Str, String field2Str) {
InputStream file = MyLoad_SaveSampleProject.class.getResourceAsStream("/main/resources/otherClasses/projects/SampleProject.xml");
try {
DocumentBuilderFactory DocBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder DocBuilder = DocBuilderFactory.newDocumentBuilder();
Document Doc = DocBuilder.parse(file);
NodeList list = Doc.getElementsByTagName("*"); //create a list with the elements of the xml file
for (int i=0; i<list.getLength(); i++) {
Node thisAttribute = list.item(i);
if (thisAttribute.getNodeName().equals("field1")) {
thisAttribute.setTextContent(field1Str);
} else if (thisAttribute.getNodeName().equals("field2")) {
thisAttribute.setTextContent(field2Str);
}
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(Doc);
StreamResult result = new StreamResult(new File("src/main/resources/otherClasses/projects/SampleProject.xml"));
transformer.transform(source, result);
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (TransformerException tfe) {
tfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (SAXException sae) {
sae.printStackTrace();
}
}
public String returnField1() {
return field1;
}
public String returnField2() {
return field2;
}
}
And this is my default XML file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><Strings>
<field1>string1</field1>
<field2>string2</field2>
</Strings>
When the save button is pressed I am using the saveSampleProject method. When the load button is pressed I am using the loadSampleProject method and then I am getting the field values with the returnField1 and returnField2 methods.
I have no idea of what could be wrong with what I'm doing. I would appreciate any suggestions.
Most probably that calling method getResourceAsStream() leads to resource caching. Since you are using File() in save method try to get InputStream on data load using File object, and not as resource.
I use Simple XML (simple-xml-2.6.2.jar) to parse xml file like:
<?xml version="1.0" encoding="UTF-8" ?>
<orderList>
<order id="1">
<name>NAME1</name>
</order>
<order id="2">
<name>NAME2</name>
</order>
</orderList>
The root Element contains subElements.
I wanna it be ArrayList, How to do it?
Here's a possible solution, hope it helps you:
Annotations of Order class:
#Root(name="order")
public class Order
{
#Attribute(name="id", required=true)
private int id;
#Element(name="name", required=true)
private String name;
public Order(int id, String name)
{
this.id = id;
this.name = name;
}
public Order() { }
// Getter / Setter
}
Example class, containing the list:
#Root(name="elementList")
public class Example
{
#ElementList(required=true, inline=true)
private List<Order> list = new ArrayList<>();
// ...
}
And here's some code for reading your code:
Serializer ser = new Persister();
Example example = ser.read(Example.class, file); // file = your xml file
// 'list' now contains all your Orders
List is an interface, ArrayList is one of its implementation, like:
List<Order> l = new ArrayList<Order>()
So if you have a List , you basically have what you want.
If I've interpreted your question correctly, you want a list of orders. I've not tested this for your setup but this works for me for a similar xml structure (assumes you have a custom class called Order):
List<Order> orders = new ArrayList<Order>();
XMLDOMParser parser = new XMLDOMParser();
AssetManager manager = context.getAssets();
InputStream stream;
try {
stream = manager.open("test.xml"); //need full path to your file here - mine is stored in assets folder
Document doc = parser.getDocument(stream);
}catch(IOException ex){
System.out.printf("Error reading xml file %s\n", ex.getMessage());
}
NodeList nodeList = doc.getElementsByTagName("order");
for (int i = 0; i < nodeList.getLength(); i++) {
Element e = (Element) nodeList.item(i); //each order item
Node order=nodeList.item(i);
subList = order.getFirstChild(); //get the name child node
orders.add(order);
}
//XMLDOMParser Class
public class XMLDOMParser {
//Returns the entire XML document
public Document getDocument(InputStream inputStream) {
Document document = null;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = factory.newDocumentBuilder();
InputSource inputSource = new InputSource(inputStream);
document = db.parse(inputSource);
} catch (ParserConfigurationException e) {
Log.e("Error: ", e.getMessage());
return null;
} catch (SAXException e) {
Log.e("Error: ", e.getMessage());
return null;
} catch (IOException e) {
Log.e("Error: ", e.getMessage());
return null;
}
return document;
}
/*
* I take a XML element and the tag name, look for the tag and get
* the text content i.e for <employee><name>Kumar</name></employee>
* XML snippet if the Element points to employee node and tagName
* is name I will return Kumar. Calls the private method
* getTextNodeValue(node) which returns the text value, say in our
* example Kumar. */
public String getValue(Element item, String name) {
NodeList nodes = item.getElementsByTagName(name);
return this.getTextNodeValue(nodes.item(0));
}
private final String getTextNodeValue(Node node) {
Node child;
if (node != null) {
if (node.hasChildNodes()) {
child = node.getFirstChild();
while(child != null) {
if (child.getNodeType() == Node.TEXT_NODE) {
return child.getNodeValue();
}
child = child.getNextSibling();
}
}
}
return "";
}
}