JAXB: Есть ли способ демаршалировать только определенные пути в XML?

У меня есть XSD, который определяет иерархию нескольких сложных типов (каждый из которых является потомком другого).

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>

Я хочу импортировать в список только комплексный тип 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 (я никогда не использовал их), но надеялся на что-то более прямолинейное.

На самом деле я использую инфраструктуру Spring 4 с пакетом spring-oxm, чтобы справиться с большим количеством работы JAXB для меня, поэтому мне бы хотелось найти простое решение, которое будет легко понять и поддерживать. Использование чего-то вроде Digester просто добавляет в мой стек больше технологий, которых я бы предпочел избегать.

Есть ли простой способ сделать это с помощью JAXB, или это выходит за рамки JAXB?


person Eric B.    schedule 25.09.2015    source источник
comment
Это точно дети друг друга? Я не вижу используемых атрибутов extension.   -  person Keith    schedule 25.09.2015
comment
@Keith Да - вы можете видеть, что структура такова: detailreport.severity.category.cwe.staticflaws.flaw   -  person Eric B.    schedule 25.09.2015
comment
Конечно - я думаю, что разделил волосы относительно семантики композиции и наследования. Дай мне подумать об этом, но я не уверен, что ты сможешь сделать то, на что надеешься. Не могли бы вы добавить в свой вопрос псевдокод, чтобы визуализировать то, что вы хотели бы увидеть?   -  person Keith    schedule 25.09.2015
comment
@Keith Я обновил вопрос, добавив еще несколько деталей, указывающих, чего я пытаюсь достичь.   -  person Eric B.    schedule 25.09.2015


Ответы (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, но единственный способ, который я вижу, это отражение. Это единственный способ?

person Eric B.    schedule 25.09.2015