我有一个XSD,它定义了几个复杂类型的层次结构(每一个都是另一个的子类型)。
,
<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>
我希望只导入complexType FlawType
到列表中。我想我可能可以使用Apache Digester来做到这一点,但我想知道是否有一些方法可以使用JAXB来做到这一点。直接反编组到detailedreport
对象,然后使用循环提取缺陷类型是可行的,但似乎有很多额外的工作。
从本质上讲,我希望能够提出一个解决方案,它会做一些事情:
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 );
我可能会将整个XML文件加载到DOM对象中,然后使用类似XPath的东西来定位所有单独的FlawType
节点,对于每个节点,使用Unmarshaller来为每个节点执行此操作,但不知道是否有更简单的方法。我假设我也可以使用某种形式的SAX解析器(我从未使用过它们),但希望有一些更直接的东西。
我实际上正在使用Spring 4框架和Spring -oxm包来为我处理大量JAXB的跑腿工作,因此我希望找到一个易于理解和维护的简单解决方案。使用像Digester这样的东西只是给我的堆栈增加了更多的技术,我宁愿避免。
是否有一种简单的方法可以用JAXB做到这一点,或者这超出了JAXB的范围?
我已经找到了一个解决方案,但我不认为这是最漂亮的可能:
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);
我希望是整洁一点的东西。对于初学者,我不喜欢必须手动搜索名为cwe
的元素。至少,我希望能够从生成的CweType类或CategoryType类中获得元素名称,但我认为这样做的唯一方法是反射。这是唯一的办法吗?