Search code examples
javaxmlparsingnullstax

Stax API XML parsing produces null results


I have been trying to get this over for a while now with little or no success. Right now, I am really out of options. I will appreciate some assistance or pointers towards the right direction.... since I believe I am not doing somethings very well.

After parsing with the code below, I have null values in most of the fields: Result{id=30c26c8a-8bdf-4d4d-8f8d-a19661f16877, name=Andriod_Office_Task, owner =generated.Owner@53d8d10a, comment=, creationTime=2016-09-09T19:30, modificationTime=2016-09-09T19:30:05+02:00, reportId=null, taskid=null, host=null, port=null, nvt=null, scanNVTVersion=null, threat=null, severity=null, description=null}

The parsing methods (other methods are excluded for brevity):

private List<Result> readDocument(XMLStreamReader parser) throws         XMLStreamException, DatatypeConfigurationException {
    List<Result> results = new ArrayList<>();

    while (parser.hasNext()) {
        int eventType = parser.next();
        switch (eventType) {
        case XMLStreamReader.START_ELEMENT:
            String elementName = parser.getLocalName();
            if (elementName.equals("result"))
                results.add(readResult(parser));
            break;
        case XMLStreamReader.END_ELEMENT:
            return results;

        }
    }
    throw new XMLStreamException("Premature end of file");
}

public Result readResult(XMLStreamReader parser) throws XMLStreamException, DatatypeConfigurationException {

    Result result = new Result();
    result.setId(parser.getAttributeValue(null, "id"));


    Report report = new Report();

    Task task = new Task();

    while (parser.hasNext()) {
        int eventType = parser.next();
        switch (eventType) {
        case XMLStreamReader.START_ELEMENT:
            String elementName = parser.getLocalName();
            if (elementName.equals("name"))
                result.setName(readCharacters(parser));
            else if (elementName.equals("host"))
                result.setHost(readCharacters(parser));
            else if (elementName.equals("owner"))
                result.setOwner(readOwner(parser));
            else if (elementName.equals("comment"))
                result.setComment(readCharacters(parser));
            else if (elementName.equals("creation_time"))

                result.setCreationTime(readCreationTime(parser));

            else if (elementName.equals("modification_time"))
                result.setModificationTime(readCharacters(parser));
            else if (elementName.equals("report"))
                report.setId(readReport(parser));
            else if (elementName.equals("task"))
                task.setId(readTask(parser));
            else if (elementName.equals("user_tags"))
                result.setUserTags(readUserTags(parser));
            else if (elementName.equals("port"))
                result.setPort(readCharacters(parser));
            else if (elementName.equals("nvt"))
                result.setNvt(readNvt(parser));
            else if (elementName.equals("scan_nvt_version"))
                result.setScanNVTVersion(readCharacters(parser));
            else if (elementName.equals("threat"))
                result.setThreat(readCharacters(parser));
            else if (elementName.equals("severity"))
                result.setSeverity(readCharacters(parser));
            else if (elementName.equals("qod"))
                result.setQod((Qod) readQod(parser));
            else if (elementName.equals("description"))
                result.setDescription(readCharacters(parser));

            break;
        case XMLStreamReader.END_ELEMENT:
        }
        return result;

    }

    throw new XMLStreamException("Premature end of file");
}

private String readCharacters(XMLStreamReader reader) throws XMLStreamException {
    StringBuilder result = new StringBuilder();
    while (reader.hasNext()) {
        int eventType = reader.next();
        switch (eventType) {
        case XMLStreamReader.CHARACTERS:
            result.append(reader.getText());
            break;
        case XMLStreamReader.END_ELEMENT:
            return result.toString();
        }
    }
    throw new XMLStreamException("Premature end of file");
}


}

The result class is below :

   @XmlRootElement
   @XmlAccessorType(XmlAccessType.FIELD)
   @JsonIgnoreProperties(ignoreUnknown = true)
   public class Result {

@XmlAttribute
private String id;

 @XmlElement
 private String name;

@XmlElement
private Task task;

@XmlElement
private String comment;

@XmlElement(name = "creation_time")
String creationTime;

@XmlElement(name = "modification_time")
private String modificationTime;

// TODO user_tags
@XmlElement
private UserTags userTags;

@XmlElement
private Owner owner;

@XmlElement
private Qod qod;

/**
 * // * The report the result belongs to (only when details were requested)
 * //
 */
@XmlElementWrapper(name = "report")
@XmlElement(name = "reportId")
private String reportId;

@XmlElement
private String host;

@XmlElement
private String port;

@XmlElement
private NVT nvt;

@XmlElement(name = "scan_nvt_version")
private String scanNVTVersion;

@XmlElement
private String threat;

@XmlElement
private String severity;

@XmlElement
private String description;

public Result() {
}

public String getId() {
    return id;
}

public void setId(String id) {
    this.id = id;
}



public Task getTask() {
    return task;
}


public void setTask(Task task) {
    this.task = task;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getComment() {
    return comment;
}

public void setComment(String comment) {
    this.comment = comment;
}

public String getCreationTime() {
    return creationTime;
}

public void setCreationTime(String creationTime) {
    this.creationTime = creationTime;
}

public String getModificationTime() {
    return modificationTime;
}

public void setModificationTime(String modificationTime) {
    this.modificationTime = modificationTime;
}

public UserTags getUserTags() {
    return userTags;
}

public void setUserTags(UserTags userTags) {
    this.userTags = userTags;
}

public Qod getQod() {
    return qod;
}

public void setQod(Qod qod) {
    this.qod = qod;
}

public Owner getOwner() {
    return owner;
}

public void setOwner(Owner owner) {
    this.owner = owner;
}

public String getReportId() {
    return reportId;
}

public void setReportId(String reportId) {
    this.reportId = reportId;
}



public String getHost() {
    return host;
}

public void setHost(String host) {
    this.host = host;
}

public String getPort() {
    return port;
}

public void setPort(String port) {
    this.port = port;
}

public NVT getNvt() {
    return nvt;
}

public void setNvt(NVT nvt) {
    this.nvt = nvt;
}

public String getScanNVTVersion() {
    return scanNVTVersion;
}

public void setScanNVTVersion(String scanNVTVersion) {
    this.scanNVTVersion = scanNVTVersion;
}

public String getThreat() {
    return threat;
}

public void setThreat(String threat) {
    this.threat = threat;
}

public String getSeverity() {
    return severity;
}

public void setSeverity(String severity) {
    this.severity = severity;
}

public String getDescription() {
    return description;
}

public void setDescription(String description) {
    this.description = description;
}

@Override
public String toString() {
    return "Result{" + "id=" + id +
     ", name=" + name + ", owner =" + owner +
            ", comment=" + comment + ", creationTime=" + creationTime + ", modificationTime=" + modificationTime
            + ", reportId=" + reportId + ", taskid=" + task + ", host=" + host + ", port=" + port + ", nvt=" + nvt
            + ", scanNVTVersion=" + scanNVTVersion + ", threat=" + threat + ", severity=" + severity
            + ", description=" + description + '}';
}

}
<get_results_response status="200" status_text="OK">
    <result id="30c26c8a-8bdf-4d4d-8f8d-a19661f16877">
        <name>Trace route</name>
        <owner>
            <name>admin</name>
        </owner>
        <comment/>
        <creation_time>2016-09-09T19:30:05+02:00</creation_time>
        <modification_time>2016-09-09T19:30:05+02:00</modification_time>
        <  id="2a6d7f75-f6b7-40b2-a792-b558fada375b"/>
        <task id="e59ac66b-5b59-4756-bace-37bb1106276d">
            <name>Andriod_Office_Task</name>
        </task>
        <user_tags>
            <count>0</count>re
        </user_tags>
        <host>172.16.53.178</host>
        <port>general/tcp</port>
        <nvt oid="1.3.6.1.4.1.25623.1.0.51662">
            <name>Traceroute</name>
            <family>General</family>
            <cvss_base>0.0</cvss_base>
            <cve>NOCVE</cve>
            <bid>NOBID</bid>
            <xref>NOXREF</xref>
            <tags>cvss_base_vector=AV:N/AC:L/Au:N/C:N/I:N/A:N|qod_type=remote_banner|solution=Block unwanted packets from escaping your network.|summary=A traceroute from the scanning server to the target system was
conducted. This traceroute is provided primarily for informational
value only. In the vast majority of cases, it does not represent a
vulnerability. However, if the displayed traceroute contains any
private addresses that should not have been publicly visible, then you
have an issue you need to correct.</tags>
            <cert/>
        </nvt>
        <scan_nvt_version>$Revision: 2837 $</scan_nvt_version>
        <threat>Log</threat>
        <severity>0.0</severity>
        <qod>
            <value>80</value>
            <type>remote_banner</type>
        </qod>
        <description>Here is the route from 192.168.14.128 to 172.16.53.178:

192.168.14.128
172.16.53.178</description>
    </result>
    <filters id="">
        <term>first=1 rows=-1 sort=name</term>
        <keywords>
            <keyword>
                <column>first</column>
                <relation>=</relation>
                <value>1</value>
            </keyword>
            <keyword>
                <column>rows</column>
                <relation>=</relation>
                <value>-1</value>
            </keyword>
            <keyword>
                <column>sort</column>
                <relation>=</relation>
                <value>name</value>
            </keyword>
        </keywords>
    </filters>
    <sort>
        <field>name
            <order>ascending</order></field>
    </sort>
    <results max="-1" start="1"/>
    <result_count>3444
        <filtered>1</filtered>
        <page>1</page></result_count>
</get_results_response>

Solution

  • After some research and attempts with some common xml parsing approaches, I ended up using jackson-dataformat-xml approach. While this might not be the best it gave me what I wanted with much less code. Basically, I had to adapt the annotations in the model classes as below :

     @JsonIgnoreProperties(ignoreUnknown=true)
     @JacksonXmlRootElement(localName = "results")
     public class Results {
    
    
    @JacksonXmlProperty(localName = "result")
    @JacksonXmlElementWrapper(useWrapping = false)
    public Result [] result;
    
    
    public Results() {
            }
    
    
    public Result[] getResult() {
        return result;
    }
    
    
    public void setResult(Result[] result) {
        this.result = result;
    }
    
    
    @Override
    public String toString() {
        return "Results [result=" + Arrays.toString(result) + "]";
    }
    

    And some adaptations for the parsing class:

    public class GetReportsResponseHandler extends   DefaultHandler<GetReportsResponse> {
    
    private XmlMapper mapper = new XmlMapper();
    public GetReportsResponseHandler() {
    super(new GetReportsResponse(), "get_reports_response");
    AnnotationIntrospector primary = new JacksonAnnotationIntrospector();
    AnnotationIntrospector secondary = new JaxbAnnotationIntrospector();
    AnnotationIntrospector pair = new AnnotationIntrospectorPair(primary,         secondary);
    mapper.setAnnotationIntrospector(pair);
    }
    
    @Override
    protected void parseStartElement(XMLStreamReader parser) throws    XMLStreamException, IOException {
        if ("report".equals(parser.getName().toString())){
            Report report = mapper.readValue(parser, Report.class);
            response.addReport(report);
        }