JAXB: Is there a way to unmarshal only specific paths in an XML?

邮差的信 提交于 2020-01-06 00:55:09

问题


I have an XSD which defines a hierarchy of several complex types (each one being a child of the other).

Ex:

<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:complexType name="FlawType">
  <xs:sequence>
    <xs:element name="mitigations" minOccurs="0" maxOccurs="1" type="tns:MitigationListType" />
    <xs:element name="exploit_desc" type="tns:LongTextType" minOccurs="0" maxOccurs="1"/>
  </xs:sequence>
</xs:complexType>


<xs:complexType name="MitigationListType">
  <xs:sequence>
    <xs:element name="mitigation" minOccurs="0" maxOccurs="unbounded" type="tns:MitigationType"/>
  </xs:sequence>
</xs:complexType>

<xs:complexType name="MitigationType">
  <xs:attribute name="action" type="xs:string" use="required"/>
  <xs:attribute name="description" type="xs:string" use="required"/>
  <xs:attribute name="user" type="xs:string" use="required"/>
  <xs:attribute name="date" type="xs:string" use="required"/>
</xs:complexType>

</xs:schema>

I'm looking to import only complexType FlawType into a list. I figure I can probably use Apache Digester to do this but was wondering if there was some way to do this with JAXB. Unmarshalling direct to a detailedreport object and then using loops to extract the FlawType is feasible, but seems like a lot of extra work.

In essence, I'm hoping to be able to come up with a solution that would do something like:

   String xml = FileUtils.readFileToString( XML_File );
   unmarshaller = JAXBContext.createUnmarshaller();
   // only unmarhsal nodes of FlawType.class from the xml file.
   List<FlawType> flawTypes = unmarshaller.unmarshal( xml, FlawType.class );

I could probably load the entire XML file into a DOM object, then use something like XPath to locate all the individual FlawType nodes and for each node, use an Unmarshaller to do it for each node, but didn't know if there was an easier way. I presume I might be able to use some form of a SAX Parser as well (I've never used them) but was hoping for something a little more straight forward.

I'm actually using the Spring 4 framework with spring-oxm package to handle a lot of the JAXB legwork for me, so would love to find a simple solution that will be easily understood and maintainable. Using something like Digester just adds more technology to my stack which I would much rather avoid.

Is there an easy way to do this with JAXB, or this is beyond the scope of JAXB?


回答1:


I have managed to find the following as a solution, but don't think it is the prettiest possible:

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

JAXBContext jc = JAXBContext.newInstance( CweType.class );
Unmarshaller u = jc.createUnmarshaller();

List<CweType> cwes = new ArrayList<>();
for( int i = 0; i < nodeList.getLength(); i++ )
    cwes.add( u.unmarshal(nodeList.item(i),  CweType.class);

I was hoping for something a little neater. For starters, I do not like the idea that I have to manually search for element named cwe. I would, at the very least, like to be able to get the element name from the generated CweType class or the CategoryType class, but the only way I can see doing that is reflection. Is that the only way?



来源:https://stackoverflow.com/questions/32773969/jaxb-is-there-a-way-to-unmarshal-only-specific-paths-in-an-xml

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!