2015-07-07 2 views
1

Я использую JAXB 2.0 и хочу, чтобы unmarshall xml получал ошибки проверки. Например, если какой-либо элемент или атрибут пропущены. Вот XML я хочу разобрать:Как размонтировать xml с разными пространствами имен

<?xml version="1.1" encoding="utf-8"?> 
<package version="2.0" xmlns="http://www.idpf.org/2007/opf"> 
    <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf"> 
    <dc:title>Title</dc:title> 
    </metadata> 
</package> 

Мои классы моделей:

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlRootElement(name = "package") 
public class Package { 
    @XmlElement(required = true) 
    public Metadata metadata; 

    @XmlAttribute(name = "version", required = true) 
    public String version; 
} 

@XmlAccessorType(XmlAccessType.FIELD) 
@XmlRootElement(name = "metadata") 
public class Metadata { 

    @XmlElement(namespace = "http://purl.org/dc/elements/1.1/", required = true) 
    public String title; 
} 

package-info.java также имеет аннотацию:

@javax.xml.bind.annotation.XmlSchema(namespace = "http://www.idpf.org/2007/opf", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED) 

и код для немаршалинг:

JAXBContext jc = JAXBContext.newInstance(Package.class); 
    Unmarshaller unmarshaller = jc.createUnmarshaller(); 

    final List<ByteArrayOutputStream> outs = new ArrayList<>(); 
    jc.generateSchema(new SchemaOutputResolver(){ 
     @Override 
     public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException { 
      ByteArrayOutputStream out = new ByteArrayOutputStream(); 
      outs.add(out); 
      StreamResult streamResult = new StreamResult(out); 
      streamResult.setSystemId(""); 
      return streamResult; 
     }}); 
    StreamSource[] sources = new StreamSource[outs.size()]; 
    for (int i=0; i<outs.size(); i++) { 
     ByteArrayOutputStream out = outs.get(i); 
     System.out.append(new String(out.toByteArray())); 
     sources[i] = new StreamSource(new ByteArrayInputStream(out.toByteArray()),""); 
    } 
    SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
    Schema schema = sf.newSchema(sources); 
    unmarshaller.setSchema(schema); 

    unmarshaller.setEventHandler(event -> { 
     System.out.append(event.toString()); 
     return true; 
    }); 
    Opf file = (Opf) unmarshaller.unmarshal(opfFile); 

Он создает эту схему:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<xs:schema elementFormDefault="qualified" version="1.0" targetNamespace="http://www.idpf.org/2007/opf" xmlns:tns="http://www.idpf.org/2007/opf" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns1="http://purl.org/dc/elements/1.1/"> 
    <xs:import namespace="http://purl.org/dc/elements/1.1/"/> 
    <xs:element name="metadata" type="tns:metadata"/> 
    <xs:element name="package" type="tns:package"/> 
    <xs:complexType name="package"> 
    <xs:sequence> 
     <xs:element ref="tns:metadata"/> 
    </xs:sequence> 
    <xs:attribute name="version" type="xs:anySimpleType" use="required"/> 
    </xs:complexType> 
    <xs:complexType name="metadata"> 
    <xs:sequence> 
     <xs:element ref="ns1:title"/> 
    </xs:sequence> 
    </xs:complexType> 
</xs:schema> 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<xs:schema version="1.0" targetNamespace="http://purl.org/dc/elements/1.1/" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xs:element name="title" type="xs:string"/> 
</xs:schema> 

И в немаршалинге он выдаст ошибку: org.xml.sax.SAXParseException: Src-решимость: не удается разрешить имя «ns1: названию» к (п) «объявление элемента ' компонент.

Как я должен аннотировать мои классы для анализа этого xml-файла?

ответ

1

Вы должны получить свои руки грязными с помощью ресурса resolver; ниже приведен рабочий код:

JAXBContext jc = JAXBContext.newInstance(Package.class); 
Unmarshaller unmarshaller = jc.createUnmarshaller(); 

final Map<String, ByteArrayOutputStream> outs = new HashMap<String, ByteArrayOutputStream>(); 

jc.generateSchema(new SchemaOutputResolver(){ 
    @Override 
    public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException{ 
     ByteArrayOutputStream out = new ByteArrayOutputStream(); 
     outs.put(suggestedFileName, out); 
     StreamResult streamResult = new StreamResult(out); 
     streamResult.setSystemId(suggestedFileName); 
     return streamResult; 
    }}); 
StreamSource[] sources = new StreamSource[outs.size()]; 
int i = 0; 
for (Map.Entry<String, ByteArrayOutputStream> entry: outs.entrySet()) { 
    System.out.append(new String(entry.getValue().toByteArray())); 
    sources[i++] = new StreamSource(new ByteArrayInputStream(entry.getValue().toByteArray()), entry.getKey()); 
} 
SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
sf.setResourceResolver(new LSResourceResolver(){ 
    @Override 
    public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId, String baseURI){ 
     ByteArrayOutputStream bout = outs.get(systemId); 
     if(bout!=null){ 
      return new DOMInputImpl(publicId, systemId, baseURI, new ByteArrayInputStream(bout.toByteArray()), null); 
     }else 
      return null; 
    } 
}); 
Schema schema = sf.newSchema(sources); 
unmarshaller.setSchema(schema); 
unmarshaller.setEventHandler(new ValidationEventHandler(){ 
    @Override 
    public boolean handleEvent(ValidationEvent event){ 
     System.out.append(event.toString()); 
     return true; 
    } 
}); 

Object obj = unmarshaller.unmarshal(new File("package.xml")); 
+1

Спасибо, но я генерирую эти схемы в памяти. Нет файлов с этими схемами на диске. Насколько я понимаю, мне нужно сообщить первой схеме, что элемент title принадлежит к другой схеме, но я не знаю, как это сделать. Но в любом случае, вы подталкиваете меня в правильном направлении. –

Смежные вопросы