Reading multi-node and attribute XML in Java - java

My XML is as follows:-
<myxml>
<resource name='book'>
<acl>
<ace person='bob' rights='rw' />
<ace person='john' rights='w' />
</acl>
</resource>
<resource name='dvd'>
<acl>
<ace person='bob' rights='w' />
</acl>
</resource>
</myxml>
I am having trouble reading this XML document.
Here is the code I tried.
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory
.newDocumentBuilder();
Document document = documentBuilder.parse(new File(fileName));
Element rootElement = xmlDocument.getDocumentElement();
NodeList resourceList= rootElement.getElementsByTagName("resource");
for (int i = 0; i < resourceList.getLength(); i++) {
Node node = resourceList.item(i);
Element element = (Element) node;
String resourceName= element.getAttribute("name");
}
Basically I want to print like "this book can be used by this person with xyz permission".
I can get the name of the book by String objectName= element.getAttribute("name"). After this I can't go.
I tried by getting child nodes but keep on getting nulls.
Any suggestions?

One option is use element.getElementsByTagName("ace") to retrieve the ace elements you're looking for:
NodeList aceList = element.getElementsByTagName("ace");
for(int j= 0; j < aceList.getLength(); j++){
Element ace = (Element) aceList.item(j);
String person = ace.getAttribute("person");
}

You just need another for loop nested inside to process <ace> elements.
NodeList resourceList = rootElement.getElementsByTagName("resource");
for (int i = 0; i < resourceList.getLength(); i++) {
Element resource = (Element) resourceList.item(i);
String book = resource.getAttribute("name");
NodeList aceList = resource.getElementsByTagName("ace");
for (int j = 0; j < aceList.getLength(); j++) {
Element ace = (Element) aceList.item(j);
System.out.println("'" + book + "' can be used by '"
+ ace.getAttribute("person") + "' with '"
+ ace.getAttribute("rights") + "' permission.");
}
}
Output :
'book' can be used by 'bob' with 'rw' permission.
'book' can be used by 'john' with 'w' permission.
'dvd' can be used by 'bob' with 'w' permission.

Related

Return values from xml, xml Iteration

I have an xml file as such
<?xml version="1.0" encoding="UTF-8"?>
<folder name="c">
<folder name="program files">
<folder name="uninstall information" />
</folder>
<folder name="users"/>
</folder>
I want to print out "c", "program files", "uninstall information" and "users" what i finally want to do is to print out only values of the name attribute with string starting from u , therefore users and uninsall information.
But i have not been able to print all the values out,
Below is my code where you can see i have tried to ways but no success so far.
public static Collection<String> folderNames(String xml, char startingLetter) throws Exception {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
FileInputStream fis = new FileInputStream("src/main/resources/test.xml");
org.xml.sax.InputSource is = new InputSource(fis);
Document doc = documentBuilder.parse(is);
NodeList nodeList = doc.getElementsByTagName("*");
for(int i =0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
/// Tried this
if(node.getNodeType() == Node.ELEMENT_NODE) {
String value = node.getTextContent();
System.out.println("value:::" +value);
}
/// tried this
// Element element = (Element)nodeList.item(i);
// NamedNodeMap attributes = element.getAttributes();
// Node nodeValue1 = nodeList.item(i);
// System.out.println(nodeValue1.getAttributes().item(i));
}
} catch (Exception e) {
e.getMessage();
}
return Collections.EMPTY_LIST;
}
for speedy test my imported classes looks like test
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
My approach without using getElementByTagsName
Document doc = documentBuilder.parse(is);
NodeList nodeList = doc.getElementsByTagName("folder");
for(int i =0; i < nodeList.getLength(); i++) {
if (nodeList.item(i).hasChildNodes()) {
for(int i1 = 0; i1 < nodeList.item(i).getChildNodes().getLength(); i1++) {
Node node = nodeList.item(i).getChildNodes().item(i);
System.out.println(node.getAttributes().item(i));
}
}
Node nodeValue1 = nodeList.item(i);
System.out.println(nodeValue1.getAttributes().item(i));
This isnt complete but it will require a recursive call, due to hierarchy in the xml
Example of printing all folder names starting with u:
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<folder name=\"c\">\n" +
" <folder name=\"program files\">\n" +
" <folder name=\"uninstall information\" />\n" +
" </folder>\n" +
" <folder name=\"users\"/>\n" +
"</folder>";
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document doc = documentBuilder.parse(new InputSource(new StringReader(xml)));
NodeList nodeList = doc.getElementsByTagName("folder");
for (int i = 0; i < nodeList.getLength(); i++) {
Element element = (Element) nodeList.item(i);
String name = element.getAttribute("name");
if (name.startsWith("u"))
System.out.println(name);
}
Output
uninstall information
users
You almost had it. First you have to identify the XML element, which you did.
if(node.getNodeType() == Node.ELEMENT_NODE) {
String value = node.getTextContent();
System.out.println("value:::" +value);
}
but instead of getting invoking getTextContent(), you need to find the attribute in that element. Some variation of the below. Of course, if there is more than one attribute you will need to accomodate looking at them all (using node.getAttributes().getLength()):
if(node.getNodeType() == Node.ELEMENT_NODE) {
if (node.getAttributes() != null) {
String name = node.getAttributes().item(0).getNodeName();
String value = node.getAttributes().item(0).getNodeValue();
System.out.println("attribute name:::" +name + " value:::" +value);
}
}

Maintaining count of XML elements using Xpath

I am a beginner in using Java programming particularly using Xpath to parse an XML file.
I am trying to develop a system that routes flights according to their weightings. I want to:
Maintain a count of flights for each location;
The system should accept a location and return the number and country to route a flight to. For every 4 flights to Japan, route the next 2 flights to China then route the next 2 flights to India and loop and to return count, continent, location name, country and weight.
I would appreciate any assistance please.
I can pass the XML data of and retrieve the different element nodes using Xpath. I attempted using SAX and STAX but prefered this method as it was clear and concise when constructing the expressions.
XML File Example:
<continent>
<location name = "asia">
<country>Japan</country>
<code>0000011111</code>
<weight>10</weight>
</location>
<location name = "asia">
<country>China</country>
<code>0000022222</code>
<weight>1</weight>
</location>
</continent>
Java Sample Code:
public static void main(String[] args) {
try {
FileInputStream file = new FileInputStream(new File("c:/continents.xml"));
DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = builderFactory.newDocumentBuilder();
Document xmlDocument = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
System.out.println("*************************");
String expression = "/continent/location";
System.out.println(expression);
String name = xPath.compile(expression).evaluate(xmlDocument);
System.out.println(name);
System.out.println("**********Parse XML File***************");
expression = "/continent/location/country|//number|//weight";
System.out.println(expression);
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());
}
System.out.println("*************************");
expression = "/continent/location[#name='asia']/number";
System.out.println(expression);
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());
}
System.out.println("*************************");
expression = "//location[country='China']";
System.out.println(expression);
Node node = (Node) xPath.compile(expression).evaluate(xmlDocument, XPathConstants.NODE);
if(null != node) {
nodeList = node.getChildNodes();
for (int i = 0;null!=nodeList && i < nodeList.getLength(); i++) {
Node nod = nodeList.item(i);
if(nod.getNodeType() == Node.ELEMENT_NODE)
System.out.println(nodeList.item(i).getNodeName() + " : " + nod.getFirstChild().getNodeValue());
}
}
}
I’m not sure I understand your goal, but if you just want to count how many flights are to a particular country, you can count the matching elements:
NodeList matches = (NodeList) xPath.evaluate(
"//country[text()='" + country + "']",
xmlDocument,
XPathConstants.NODESET);
int matchCount = matches.getLength();

XML parsing to Java - getting root attribute value

I'm having a slight problem with XML parsing.
I'm creating a function where the parameter is a certain "element" from the XML file.
When found, I want to return the value of the root attribute.
Here's my code:
FileInputStream file = new FileInputStream(new File("C:\\Users\\Grizzly\\Java\\Projet_16_17-20161214\\bdd.xml"));
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(file);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("type");
for (int temp = 0; temp < nList.getLength(); temp++)
{
Node nNode = nList.item(temp);
if(nNode.toString().equalsIgnoreCase(element))
{
Element eElement = (Element) nNode;
System.out.println("Taxe= "+ eElement.getAttribute("taxe"));
}
}
}
Any idea on how to do this?
Here's my XML file:
<?xml version="1.0"?>
-<types>
-<type id="Nourriture" taxe="0.1">
<element>pomme</element>
<element>fraise</element>
<element>fromage</element>
<element>viande rouge </element>
</type>
-<type id="Matiere Premiere" taxe="0.2">
<element>fer</element>
<element>polypropylene</element>
</type>
-<type id="Element Solide" taxe="0.3">
<element>voiture</element>
<element>planche surf</element>
<element>pistolet</element>
</type>
</types>
In my code, I tried to get the elements of a certain node from the nodelist and then compare it to the the string "element" which is the input of the user, and if they match it will check the attribute value of taxe linked to it.
Thanks in advance.
EDIT: I'm getting closer to what I need:
NodeList nList = doc.getElementsByTagName("type");
for (int temp = 0; temp < nList.getLength(); temp++)
{
Node nNode = nList.item(temp);
NodeList nChildren = nNode.getChildNodes();
Element eElement = (Element) nNode;
for(int i = 0; i < nChildren.getLength(); i++)
{
String onElement = eElement.getElementsByTagName("element").item(i).getTextContent();
if(onElement.equalsIgnoreCase(element))
{
System.out.println("id : " + eElement.getAttribute("id"));
System.out.println("taxe : " + eElement.getAttribute("taxe"));
break;
}
}
}
But it's only reading the first element... and item(i) isn't working.
Any idea?
If I understand you correctly, you are trying to fetch specific attributes (id and taxe) of all the document nodes having at least one child element with specific name (element).
Although the problem can be solved by iterating the DOM and keeping the states, I would rather delegate this task to XPath. A code with XPath will look cleaner and be more maintainable. For example, in order to fetch all elements having attributes id and taxe and a child element element you can use an XPath expression like //*[#id and #taxe element]. The matching nodes are fetched in a single line. You can simply iterate the nodes and collect the attributes as shown in the following example.
Example
public static void main(String args[]) {
String element = args.length > 0 ? args[0] : "element";
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder builder = factory.newDocumentBuilder();
FileInputStream file = new FileInputStream(new File("/some/file.xml"));
Document doc = builder.parse(file);
XPath xPath = XPathFactory.newInstance().newXPath();
String expression = "//*[#id and #taxe and " + element + "]";
NodeList nodeList = (NodeList) xPath.compile(expression)
.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
NamedNodeMap attributes = node.getAttributes();
for (int j = 0; j < attributes.getLength(); j++) {
Node aNode = attributes.item(j);
System.out.printf(
"%s: %s\n",
aNode.getNodeName(),
aNode.getNodeValue()
);
}
}
} catch (Exception e) {
System.err.println(e.getMessage());
System.exit(1);
}
}
Sample Output
id: Nourriture
taxe: 0.1
id: Matiere Premiere
taxe: 0.2
id: Element Solide
taxe: 0.3
Note, the sample above prints all attributes of the parent element. If you want to print only specific ones, you can, obviously, add a trivial check like this:
String aName = aNode.getNodeName();
if (aName.equals("taxe")) { // ...
But you can actually filter out the attributes with XPath:
String expression = "//*[ " + element + "]/#*[name() = 'id' or name() = 'taxe']";
NodeList nodeList = (NodeList) xPath.compile(expression)
.evaluate(doc, XPathConstants.NODESET);
for (int i = 0; i < nodeList.getLength(); i++) {
Node node = nodeList.item(i);
System.out.printf("%s: %s\n", node.getNodeName(), node.getNodeValue());
}
The XPath expression above fetches all attribute nodes having names equal to whether id, or taxe. If you want all attributes, simply remove the last condition:
String expression = "//*[ " + element + "]/#*";

Java XML Reading

I've been wondering how to read XML files, but before you answer, read the whole post.
For example I have:
<?xml version="1.0" encoding="UTF-8"?>
<messages>
<incoming id="0" class="HelloIlikeyou" />
</messages>
What I want, is get all values from the tag . I want to place it in a dictionary, which key is incoming/outgoing, and then it will contain a list of Pair as value, with as key the id value and as value the class value.
So I got this:
HashMap<String, List<Pair<Integer, String>>> headers = new HashMap<>();
Then it will store this:
HashMap.get("incoming").add(new Pair<>("0", "HelloIlikeyou"));
But I don't know how to do it, I already got a part but it aint working:
File xml = new File(file);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(xml);
doc.getDocumentElement().normalize();
NodeList nodes = doc.getElementsByTagName("messages");
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
System.out.println("Type: " + node.getNodeValue() + " packet ID " + node.getUserData("id"));
}
You can use JAXB, i think that is the best way. take a look of this:
Jaxb tutorial
This is what you want:
public static void main(final String[] args)
throws ParserConfigurationException, SAXException, IOException {
File xml = new File(file);
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(xml);
doc.getDocumentElement().normalize();
NodeList nodes = doc.getElementsByTagName("messages");
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
for (int j = 0; j < node.getChildNodes().getLength(); j++) {
Node child = node.getChildNodes().item(j);
if (!child.getNodeName().equals("#text")) {
NamedNodeMap attributes = child.getAttributes();
System.out.println("Type: " + child.getNodeName()
+ " packet ID " + attributes.getNamedItem("id")
+ " - class: " + attributes.getNamedItem("class"));
}
}
}
}
This gives me the following output:
Type: incoming packet ID id="0" - class: class="HelloIlikeyou"
Node node = nodes.item(i);
if (node instanceOf Element) {
Element elem = (Element)node;
String id = elem.getAttribute("id");
...
So you were almost there. The W3C classes are a bit old-stylish.
Use one of the many available libraries that will do that for you, for example XStream:
http://x-stream.github.io/

XML parsing. How can I get child's child?

I'm trying to parse this XML in Java:
<entities>
<entity name="product_section" id="1">
<product_type>3</product_type>
<section_type>1</section_type>
<name>Empresa</name>
<description>d</description>
<position>1</position>
<align>left</align>
<files section_id="1">
<ico id="ico_1" type="normal" src="sections/1/icons/ico.png"></ico>
<ico id="ico_2" type="hover" src="sections/1/icons/ico.png"></ico>
<ico id="ico_3" type="active" src="sections/1/icons/ico.png"></ico>
<img id="img_1" type="normal" src="sections/1/img/pestanya.png"></img>
<img id="img_2" type="hover" src="sections/1/img/pestanya-hover.png"></img>
<img id="img_3" type="active" src="sections/1/img/pestanya-active.png"></img>
<background id="background_1" type="background" position="1" src="sections/1/background/bg1.png"></background>
<background id="background_2" type="background" position="2" src="sections/1/background/bg2.png"></background>
<background id="background_3" type="background" position="3" src="sections/1/background/bg3.png"></background>
</files>
</entity>
But I just achieved to loop through Entities, getting all Entity and each <product_type>, <section_type>, etc.
But I want to loop through files too.
This is my implementation so far:
try {
File contingut = new File("xmlfile.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(contingut);
doc.getDocumentElement().normalize();
System.out.println("root of xml file " + doc.getDocumentElement().getNodeName());
//loop a cada entity
NodeList nodes = doc.getElementsByTagName("entity");
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
Element element = (Element) node;
System.out.println("product_type: " + getValue("product_type", element));
System.out.println("section_type: " + getValue("section_type", element));
System.out.println("name: " + getValue("name", element));
System.out.println("description: " + getValue("description", element));
System.out.println("position: " + getValue("position", element));
System.out.println("align: " + getValue("align", element));
}
} catch (Exception e){
e.printStackTrace();
}
getValue function is:
private static String getValue(String tag, Element element) {
NodeList nodes = element.getElementsByTagName(tag).item(0).getChildNodes();
Node node = (Node) nodes.item(0);
return node.getNodeValue();
}
I've done lot of google search, and all I find are "simple" examples, with a parent, and a child, but not child's child.
Any help would be appreciated.
At first one suggestion:
check element type after this Element element = (Element) node;
use this code or something like this :
if (element.getNodeType() == Element.ELEMENT_NODE) { // do smth}
and answer to your question:
You can simply rewrite you code. after you create element you can get all it's child elements by using element.getChildNodes();
it gives you all child tags. After that you write simple for loop where you get each node element from node list like this :
NodeList nodes = element.getChildNodes();
for(int i =0; i < nodes.getLength(); i++){
Element child = (Element) nodes.item(i);
if(child.getNodeType() == Element.ELEMENT_NODE){
String tagName = child.getTagName();
if(!tagName.equals("files")){
System.out.println(tagName + " : " + child.getTextContent());
}else{
NodeList filesChilds = child.getChildNodes();
for(int j = 0; j < filesChilds.getLength(); j++){
//and like above
}
}
}
}

Categories