JAXB: Есть ли способ разархивировать только определенные пути в XML?
У меня есть 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
объект, а затем использование циклов для извлечения FlawType выполнимо, но кажется, много дополнительной работы.
По сути, я надеюсь, что смогу найти решение, которое бы делало что-то вроде:
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 Parser (я никогда не использовал их), но надеялся на что-то более прямолинейное.
Я на самом деле использую среду Spring 4 с пакетом spring-oxm, чтобы справиться со многими трудностями JAXB, поэтому мне очень хотелось бы найти простое решение, которое будет легко понять и поддерживать. Использование чего-то вроде Digester просто добавляет больше технологий в мой стек, чего я бы скорее избегал.
Есть ли простой способ сделать это с JAXB, или это выходит за рамки JAXB?
1 ответ
Мне удалось найти следующее решение, но я не думаю, что это самое красивое из возможных:
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, но единственный способ увидеть это - отражение. Это единственный способ?