How to extract attribute values from xml file with Stax?

java, stax, xml, xml-parsing

Solution

I see 3 issues with your code here:

You are retrieving `hireday` instead of `hiredate` tag from XML; should be: `if ("hiredate".equals(reader.getLocalName()))`

You are retrieving the individual attributes with a namespace where your XML does not have any. Change it to `NULL`, like:

`int yearAttr = Integer.parseInt(reader.getAttributeValue(null, "year"));`

Calendar class in Java considers months starting from 0 (0 being January). Hence your value 12 would move on to the next year. You may want to subtract 1 from the month value to get the desired output.

`currentEmployee.setHireDay(yearAttr, monthAttr - 1, dayAttr);`

Your modified `parseEmployee()`:

public List<Employee> parseEmployee() throws XMLStreamException {
        while (reader.hasNext()) {
            int event = reader.next();

            switch (event) {
            case XMLStreamConstants.START_ELEMENT:
                if ("employee".equals(reader.getLocalName())) {
                    currentEmployee = new Employee();
                }
                if ("staff".equals(reader.getLocalName())) {
                    employeeList = new ArrayList<>();
                }
                if ("hiredate".equals(reader.getLocalName())) {
                    int yearAttr = Integer.parseInt(reader.getAttributeValue(
                            null, "year"));
                    int monthAttr = Integer.parseInt(reader.getAttributeValue(
                            null, "month"));
                    int dayAttr = Integer.parseInt(reader.getAttributeValue(
                            null, "day"));

                    currentEmployee
                            .setHireDay(yearAttr, monthAttr - 1, dayAttr);
                }
                break;

            case XMLStreamConstants.CHARACTERS:
                tagContent = reader.getText().trim();
                break;

            case XMLStreamConstants.END_ELEMENT:
                switch (reader.getLocalName()) {
                case "employee":
                    employeeList.add(currentEmployee);
                    break;
                case "name":
                    currentEmployee.setName(tagContent);
                    break;
                case "salary":
                    currentEmployee.setSalary(Double.parseDouble(tagContent));
                    break;
                }
            }
        }
        return employeeList;
    }

Now you get the correct output:

Employee { name=Carl Cracker, salary=75000.0, hireDay=Tue Dec 15 00:00:00 IST 1987 }
Employee { name=Harry Hacker, salary=50000.0, hireDay=Sun Oct 01 00:00:00 IST 1989 }
Employee { name=Tony Tester, salary=40000.0, hireDay=Thu Mar 15 00:00:00 IST 1990 }

Problem

I have to parse xml file with stax and I did mostly what I need except one point. My code logic doesn't extract attributes at right. My output looks next: ``` Employee { name=Carl Cracker, salary=75000.0, hireDay=null } Employee { name=Harry Hacker, salary=50000.0, hireDay=null } Employee { name=Tony Tester, salary=40000.0, hireDay=null } ``` Here is content of xml file: ``` <?xml version="1.0" encoding="UTF-8"?> <staff xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="newEmployee.xsd"> <employee> <name>Carl Cracker</name> <salary>75000</salary> <hiredate year="1987" month="12" day="15" /> </employee> <employee> <name>Harry Hacker</name> <salary>50000</salary> <hiredate year="1989" month="10" day="1" /> </employee> <employee> <name>Tony Tester</name> <salary>40000</salary> <hiredate year="1990" month="3" day="15" /> </employee> </staff> ``` Here is my code: ``` class StaxXmlParser { private List<Employee> employeeList; private Employee currentEmployee; private String tagContent; private XMLStreamReader reader; public StaxXmlParser(String filename) { employeeList = null; currentEmployee = null; tagContent = null; try { XMLInputFactory factory = XMLInputFactory.newFactory(); reader = factory.createXMLStreamReader(new FileInputStream(new File(filename))); parseEmployee(); } catch (Exception e) { e.printStackTrace(); } } public List<Employee> parseEmployee() throws XMLStreamException { while (reader.hasNext()) { int event = reader.next(); switch (event) { case XMLStreamConstants.START_ELEMENT: if ("employee".equals(reader.getLocalName())) { currentEmployee = new Employee(); } if ("staff".equals(reader.getLocalName())) { employeeList = new ArrayList<>(); } if ("hireday".equals(reader.getLocalName())) { int yearAttr = Integer.parseInt(reader.getAttributeValue(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "year")); int monthAttr = Integer.parseInt(reader.getAttributeValue(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "month")); int dayAttr = Integer.parseInt(reader.getAttributeValue(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "day")); currentEmployee.setHireDay(yearAttr, monthAttr, dayAttr); } break; case XMLStreamConstants.CHARACTERS: tagContent = reader.getText().trim(); break; case XMLStreamConstants.END_ELEMENT: switch (reader.getLocalName()) { case "employee": employeeList.add(currentEmployee); break; case "name": currentEmployee.setName(tagContent); break; case "salary": currentEmployee.setSalary(Double.parseDouble(tagContent)); break; } } } return employeeList; } } ``` here is content of `Employee` class: ``` class Employee { private String name; private double salary; private Date hireDay; public Employee() {} public Employee(String n, double s, int year, int month, int day) { name = n; salary = s; GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day); // GregorianCalendar uses 0 for January hireDay = calendar.getTime(); } public String getName() { return name; } public double getSalary() { return salary; } public Date getHireDay() { return hireDay; } public void setName(String name) { this.name = name; } public void setSalary(double salary) { this.salary = salary; } public void setHireDay(Date hireDay) { this.hireDay = hireDay; } public void setHireDay(int year, int month, int day) { GregorianCalendar calendar = new GregorianCalendar(year, month, day); this.hireDay = calendar.getTime(); } public void raiseSalary(double byPercent) { double raise = salary * byPercent / 100; salary += raise; } @Override public String toString() { return String.format("Employee { name=%s, salary=%s, hireDay=%s }", name, salary, hireDay); } @Override public int hashCode() { return super.hashCode(); } @Override public boolean equals(Object obj) { return super.equals(obj); } } ``` How to extract attributes by stax?

Original source