Jimmy
Jimmy

Reputation: 21

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?

Upvotes: 2

Views: 1919

Answers (1)

Ruslan Osmanov
Ruslan Osmanov

Reputation: 21492

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 + "]/@*";

Upvotes: 1

Related Questions