2015-04-14 22 views
6

Używam Jaxb2 i Spring. Próbuję anulować niektóre XML, które są wysyłane przez 2 moich klientów.Jaxb ignoruje przestrzeń nazw w unmarshalling

Do tej pory miałem tylko do obsługi jednego klienta, który wysłał kilka xml jak poniżej:

<foo xmlns="com.acme"> 
    <bar>[...]</bar> 
<foo> 

, który jest związany z POJO tak:

@XmlType(name = "", propOrder = {"bar"}) 
@XmlRootElement(name = "Foo") 
public class Foo { 

    @XmlElement(name = "Bar") 
    private String bar; 

    [...] 
} 

odkryłem, że poprzedni programista zakodował przestrzeń nazw w unmarshallerze, aby działał.

Teraz drugi klient wysyła ten sam plik XML, ale zmienia przestrzeń nazw!

<foo xmlns="com.xyz"> 
    <bar>[...]</bar> 
<foo> 

Oczywiście unmarshaller nie wycofać, ponieważ spodziewa się {com.acme}foo zamiast {com.xyz}foo. Niestety, prośba klienta o zmianę kodu XML nie jest możliwa.

Co próbowałem:

1) W application-context.xml, szukałem dla konfiguracji, która pozwoliłaby mi się ignorować nazw, ale nie mógł znaleźć jednego:

<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> 
    <property name="packagesToScan"> 
    <list> 
     <value>com.mycompany.mypkg</value> 
    </list> 
    </property> 
    <property name="marshallerProperties"> 
    <map> 
     <entry key="???"><value type="java.lang.Boolean">false</value></entry> 
    </map> 
    </property> 
</bean> 

wydaje się, że jedynymi dostępnymi opcjami są te wymienione w Javadoc Jaxb2Marshaller:

/** 
* Set the JAXB {@code Marshaller} properties. These properties will be set on the 
* underlying JAXB {@code Marshaller}, and allow for features such as indentation. 
* @param properties the properties 
* @see javax.xml.bind.Marshaller#setProperty(String, Object) 
* @see javax.xml.bind.Marshaller#JAXB_ENCODING 
* @see javax.xml.bind.Marshaller#JAXB_FORMATTED_OUTPUT 
* @see javax.xml.bind.Marshaller#JAXB_NO_NAMESPACE_SCHEMA_LOCATION 
* @see javax.xml.bind.Marshaller#JAXB_SCHEMA_LOCATION 
*/ 
public void setMarshallerProperties(Map<String, ?> properties) { 
    this.marshallerProperties = properties; 
} 

2) Próbowałem też skonfigurować unmarshaller w kodzie:

try { 
    jc = JAXBContext.newInstance("com.mycompany.mypkg"); 

    Unmarshaller u = jc.createUnmarshaller(); 
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 
    dbf.setNamespaceAware(false);//Tried this option. 

    DocumentBuilder db = dbf.newDocumentBuilder(); 
    Document doc = db.parse(xmlFile.toFile()); 
    u.unmarshal(new DOMSource(doc)); 
    return (Foo)u.unmarshal(new StreamSource(xmlFile.toFile())); 
} catch (ParserConfigurationException | SAXException | IOException | JAXBException e) { 
    LOGGER.error("Erreur Unmarshalling CPL"); 
} 

3) innej formie z SAXParser:

try { 
    jc = JAXBContext.newInstance("com.mycompany.mypkg"); 
    Unmarshaller um = jc.createUnmarshaller(); 
    final SAXParserFactory sax = SAXParserFactory.newInstance(); 
    sax.setNamespaceAware(false); 
    final XMLReader reader = sax.newSAXParser().getXMLReader(); 
    final Source er = new SAXSource(reader, new InputSource(new FileReader(xmlFile.toFile()))); 
    return (Foo)um.unmarshal(er); 
}catch(...) {[...]} 

Ten działa! Ale nadal wolałbym móc wyposażyć Unmarshallera bez potrzeby brzydkiego conf za każdym razem.

Odpowiedz

1

Świadomość o nazwach jest cechą czytnika dokumentów/budowniczego/parsera, a nie koordynatorów. Elementy XML z różnych przestrzeni nazw reprezentują różne obiekty == obiektów, więc nie można ich zignorować.

Prawidłowo wyłączyłeś przestrzenie nazw w czytniku SAX i, jak powiedziałeś, zadziałało. Nie rozumiem twojego problemu z tym, twój marshaller nadal może być wstrzykiwany, różnica polega na uzyskaniu danych wejściowych.

Ta sama sztuczka z narzędziem do tworzenia dokumentów powinna również zadziałać (przetestuję to później), podejrzewam, że nadal korzystałeś z programu Marshall z "zakodowaną" przestrzenią nazw, ale dokument był wolny od przestrzeni nazw.

W moim projekcie używam XSLT do rozwiązania podobnego problemu. Ustawienie świadomości przestrzeni nazw jest zdecydowanie prostszym rozwiązaniem. Ale dzięki XSLT mogłem usunąć niektóre przestrzenie nazw, a mój plik wejściowy xml nie zawsze jest identyczny (ignorując przestrzenie nazw), a czasami muszę zmienić nazwę kilku elementów, aby XSLT zapewniał mi dodatkową elastyczność.

Aby usunąć nazw można użyć takiego szablonu XSLT:

<xsl:stylesheet version="1.0" xmlns:e="http://timet.dom.robust.ed" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
<xsl:template match="/"> 
    <xsl:copy> 
     <xsl:apply-templates /> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="*"> 
    <xsl:element name="{local-name()}"> 
     <xsl:apply-templates select="@* | node()" /> 
    </xsl:element> 
</xsl:template> 

<xsl:template match="@*"> 
    <xsl:attribute name="{local-name()}"> 
     <xsl:value-of select="."/> 
    </xsl:attribute> 
</xsl:template> 

<xsl:template match="text() | processing-instruction() | comment()"> 
    <xsl:copy /> 
</xsl:template> 
</xsl:stylesheet> 

Następnie w Javie przed unmarshalling I przekształcenia danych wejściowych:

Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource); 
Source source = new DOMSource(xml); 
DOMResult result = new DOMResult(); 
transformer.transform(source, result); 
Powiązane problemy