2010-06-11 21 views
12

Przepraszam jeśli to zostało odebrane, ale warunki wyszukiwania używam (tj JAXB @XmlAttribute skondensowane lub JAXB XML marszałka na ciąg różnych wyników) nie wymyślają niczego.JAXB Marszałków XML inaczej OutputStream vs. StringWriter

Używam JAXB do usuwania/oznaczania obiektów adnotowanych adnotacjami @XmlElement i @XmlAttribute. Mam klasę formatyzatora, która zapewnia dwie metody - jedna opakowuje metodę marshal i akceptuje obiekt do marszałka i OutputStream, druga po prostu akceptuje obiekt i zwraca wynik XML jako ciąg. Niestety, metody te nie zapewniają tego samego wyjścia dla tych samych obiektów. Kiedy Organizowanie do pliku, proste pól obiektu wewnętrznie oznaczone @XmlAttribute są drukowane jako:

<element value="VALUE"></element> 

chwili gdy Organizowanie do String, są to:

<element value="VALUE"/> 

wolałbym drugi format obu przypadkach , ale jestem ciekawy, jak kontrolować różnicę i zadowalałoby to, że są tacy sami niezależnie. Stworzyłem nawet jednego statycznego koordynatora, którego używają obie metody do eliminowania różnych wartości instancji. Kod formatowania następująco:

/** Marker interface for classes which are listed in jaxb.index */ 
public interface Marshalable {} 

/** Local exception class */ 
public class XMLMarshalException extends BaseException {} 

/** Class which un/marshals objects to XML */ 
public class XmlFormatter { 
    private static Marshaller marshaller = null; 
    private static Unmarshaller unmarshaller = null; 

    static { 
     try { 
      JAXBContext context = JAXBContext.newInstance("path.to.package"); 
      marshaller = context.createMarshaller(); 
      marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
      marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); 

      unmarshaller = context.createUnmarshaller(); 
     } catch (JAXBException e) { 
      throw new RuntimeException("There was a problem creating a JAXBContext object for formatting the object to XML."); 
     } 
    } 

    public void marshal(Marshalable obj, OutputStream os) throws XMLMarshalException { 
     try { 
      marshaller.marshal(obj, os); 
     } catch (JAXBException jaxbe) { 
      throw new XMLMarshalException(jaxbe); 
     } 
    } 

    public String marshalToString(Marshalable obj) throws XMLMarshalException { 
     try { 
      StringWriter sw = new StringWriter(); 
      return marshaller.marshal(obj, sw); 
     } catch (JAXBException jaxbe) { 
      throw new XMLMarshalException(jaxbe); 
     } 
    } 
} 

/** Example data */ 
@XmlType 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Data { 

    @XmlAttribute(name = value) 
    private String internalString; 
} 

/** Example POJO */ 
@XmlType 
@XmlRootElement(namespace = "project/schema") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Container implements Marshalable { 

    @XmlElement(required = false, nillable = true) 
    private int number; 

    @XmlElement(required = false, nillable = true) 
    private String word; 

    @XmlElement(required = false, nillable = true) 
    private Data data; 
} 

podstawniki R esult wywoływania marshal(container, new FileOutputStream("output.xml")) i marshalToString(container) są następujące:

wyjściowe do pliku

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<ns2:container xmlns:ns2="project/schema"> 
    <number>1</number> 
    <word>stackoverflow</word> 
    <data value="This is internal"></data> 
</ns2:container> 

i

wyjście do String

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<ns2:container xmlns:ns2="project/schema"> 
    <number>1</number> 
    <word>stackoverflow</word> 
    <data value="This is internal"/> 
</ns2:container> 
+0

Dziękuję za czyszczenie, że się trochę, miałem problemy nie mający XML interpretowane. – Andy

+0

Dalsze badania wykazały, że to, czego szukam, to możliwość kontrolowania, czy JAXB zapisuje "puste elementy" w stylu HTML (sparowane tagi) lub XML (pojedynczy tag). W innych dostawcach JAXB, takich jak JaxMe, jest to właściwość, którą można ustawić, ale najwyraźniej nie w JAXB. Zastanawiam się tylko, dlaczego jest różny w zależności od typu miejsca docelowego. Wiem, że są one funkcjonalnie równoważne, ale potrzebuję ich, aby były identyczne do pracy z naszym systemem. Jakieś pomysły? – Andy

Odpowiedz

8

Wygląda na to, że może to być "błąd" w JAXB.Patrząc na źródła, wzywa do marszałka() tworzenie różnych pisarzy w zależności od typu parametru wyjściowego/Scenariusz:

public void marshal(Object obj, OutputStream out, NamespaceContext inscopeNamespace) throws JAXBException { 
    write(obj, createWriter(out), new StAXPostInitAction(inscopeNamespace,serializer)); 
} 

public void marshal(Object obj, XMLStreamWriter writer) throws JAXBException { 
    write(obj, XMLStreamWriterOutput.create(writer,context), new StAXPostInitAction(writer,serializer)); 
} 

implementacje pisarzy jest inny w odniesieniu do tego, jak radzą sobie „pustych elementów”. Powyższy kod pochodzi z:

jaxb-ri \ runtime \ src \ com \ sun \ xml \ bind \ v2 \ runtime \ MarshallerImpl.java.

Dwaj pisarze jesteś tworząc są:

JAXB-ri \ Runtime \ src \ com \ Sun \ xml \ wiążą \ v2 \ Runtime \ Wyjście \ UTF8XmlOutput.java

JAXB-ri \ Runtime \ src \ com \ sun \ xml \ bind \ v2 \ runtime \ output \ XMLStreamWriterOutput.java

+4

Dokładniej jest to błąd w implementacji Metro JAXB. Inne implementacje JAXB, takie jak EclipseLink JAXB (MOXy), nie mają tego błędu. –

1

nie wiem dlaczego JAXB robi to - a nawet jeśli jest to JAXB - jeśli JAXB jest ou tputting XML poprzez SAXContentHandler na przykład, to nie ma bezpośredniej kontroli nad tworzeniem tagów zamykających.

Aby uzyskać spójne zachowanie, można zawinąć OutputStream w OutputStreamWriter, np.

public void marshal(Marshalable obj, OutputStream os) throws XMLMarshalException { 
     try { 
      marshaller.marshal(obj, new OutputStreamWriter(os, "UTF-8")); 
     } catch (JAXBException jaxbe) { 
      throw new XMLMarshalException(jaxbe); 
     } 
    } 

Według tych samych zasad, można zobaczyć, co się dzieje, jeśli owinąć StringWriter w PrintWriter. Być może istnieje jakiś niestandardowy kod, który wykrywa StringWriter, aby zachować krótki wynik. Brzmi mało prawdopodobne, ale nie mam innego wyjaśnienia.

+0

Skończyłem robiąc dokładnie to przed sprawdzeniem tutaj i otrzymałem spójne dane wyjściowe. Dzięki. – Andy

0

Dlaczego to ma znaczenie? < atrybut tag = „wartość”> </tag> jest równoważne < tag atrybut = „wartość” /> w xml

+0

Rozumiem, że są one funkcjonalnie równoważne, ale w aplikacji, do której koduję, są pewne osobliwości, które wymagają leksykograficznie identycznych wyników. – Andy

2

Dobrą wiadomością jest to, że JAXB jest specyfikacja z więcej niż jednej realizacji (podobnie jak WZP). Jeśli jedna realizacja nie spełnia Twoich potrzeb, inne są dostępne takie jak EclipseLink JAXB (Moxy):

+0

Rzeczywiście, ponieważ ten link jest już nieistniejący –