1

This is related to my prior question which was more directed towards JAXB in general. But this question is more related specifically to the unmarshaller in spring-oxm. I'm looking to see if I can use the spring-oxm unmarshaller to unmarshal only specific elements from my XML.

My XSD is:

<xs:schema version="1.3"
  targetNamespace="https://www.domain.com/schema/reports/export/1.0"
  xmlns:tns="https://www.domain.com/schema/reports/export/1.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  elementFormDefault="qualified">

<xs:element name="detailedreport">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="severity" minOccurs="6" maxOccurs="6" type="tns:SeverityType" />
    </xs:sequence>
    </xs:complexType>
</xs:element>

<xs:complexType name="SeverityType">
  <xs:sequence>
    <xs:element name="category" minOccurs="0" maxOccurs="unbounded" type="tns:CategoryType"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="CategoryType">
  <xs:sequence>
    <xs:element name="cwe" maxOccurs="unbounded" type="tns:CweType"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="CweType">
  <xs:sequence>
    <xs:element name="staticflaws" type="tns:FlawListType" minOccurs="0"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="FlawListType">
  <xs:sequence>
    <xs:element name="flaw" minOccurs="0" maxOccurs="unbounded" type="tns:FlawType" />
  </xs:sequence>
</xs:complexType>
</xs:schema>

Using some preprocessing, I can find all Nodes of type "cwe":

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder(); 
    Document doc = db.parse(IOUtils.toInputStream(xml));
    NodeList nodeList = doc.getElementsByTagName("cwe");

Using a JAXBUnmarshaller, I can manage to unmarshal my object:

    JAXBContext jc = JAXBContext.newInstance( CweType.class );
    Unmarshaller u = jc.createUnmarshaller();
    u.unmarshal(new DOMSource(nodeList.item(0)),  CweType.class);

However, if I try to use the concept of spring-oxm unmarshaller, I get an error.

    Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
    jaxb2Marshaller.setClassesToBeBound(CweType.class);
    jaxb2Marshaller.unmarshal(new DOMSource(nodeList.item(0)));



org.springframework.oxm.UnmarshallingFailureException: JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"cwe"). Expected elements are (none)
    at org.springframework.oxm.jaxb.Jaxb2Marshaller.convertJaxbException(Jaxb2Marshaller.java:911)
    at org.springframework.oxm.jaxb.Jaxb2Marshaller.unmarshal(Jaxb2Marshaller.java:784)
    at org.springframework.oxm.jaxb.Jaxb2Marshaller.unmarshal(Jaxb2Marshaller.java:753)

@M.Deinum suggested in the comments to try XPath, but I have not feared any better - throwing the same error at unmarshal time:

   XPath xPath = XPathFactory.newInstance().newXPath();
    NodeList xpnl = (NodeList)xPath.compile("//cwe").evaluate(doc, XPathConstants.NODESET);
    jaxb2Marshaller.unmarshal(new DOMSource(xpnl.item(0)));

What am I doing wrong? Is there something wrong with the way I am creating my DOMSource()? Why am I able to unmarshal using the JAXBUnmarshaller directly, but not using the Spring wrapper? Is there anyway to explicitly declare via the spring-oxm unmarshaller the declaredType?

CweType.java:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "CweType", propOrder = {
    "description",
    "staticflaws",
    "dynamicflaws",
    "manualflaws"
})
public class CweType {

    @XmlElement(required = true)
    protected CweType.Description description;
    protected FlawListType staticflaws;
    protected FlawListType dynamicflaws;
    protected FlawListType manualflaws;
    @XmlAttribute(name = "cweid", required = true)
    @XmlSchemaType(name = "positiveInteger")
    protected BigInteger cweid;
    ...
    ....
Community
  • 1
  • 1
Eric B.
  • 23,425
  • 50
  • 169
  • 316
  • Why? Just use the marshaller and use an XPath expression to retrieve the elements you want. No need to hack around with the document yourself. – M. Deinum Sep 25 '15 at 19:23
  • @M.Deinum Won't the end result be the same? XPath will just return the elements I want and then will still need to unmarshal them. It is the unmarshalling that is causing me the problem - I question if it is b/c the DeclaredType is not annotated with @XMLRootElement and without being able to explicity indicate the declared type to the `spring-oxm` marshaller, it is unable to determine which type it is. But that is just a guess. – Eric B. Sep 25 '15 at 19:25
  • The path will just work without doing any hacking around you are trying to work around the framework instead of working with the framework. – M. Deinum Sep 25 '15 at 19:27
  • @M.Deinum Is that using raw XPath or something from within Spring? B/c if I try to use basic XPath, I get the same error (I've updated the question to include my attempt to use XPath). – Eric B. Sep 25 '15 at 20:01

1 Answers1

1
 public static CweType unmarshal(DOMSource node) throws JAXBException {
    JAXBContext jaxbContext = JAXBContext.newInstance(CweType.class);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();

    JAXBElement<CweType> root = jaxbUnmarshaller.unmarshal(node, CweType.class);
    CweType cweType= root.getValue();

    LOGGER.info(cweType.toString());
    return cweType;
}

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder(); 
Document doc = db.parse(IOUtils.toInputStream(xml));
NodeList nodeList = doc.getElementsByTagName("cwe");
CweType type = unmarshal(new DOMSource(nodeList.item(0));

I hope this can be helpful !

Lazar Lazarov
  • 2,412
  • 4
  • 26
  • 35