2012-10-17 51 views
3

通用適配器比方說,我有類人:爲JAXB

class Person{ 
    String firstName; 
    String lastName; 
    String email; 
} 

XML的格式有:

<person> 
<firstName value="asd" /> 
<lastName value="bcd" /> 
<email value="qwe" /> 
</person> 

我可以解組/元帥這個類使用領域FirstNameAdapter的每個 自己XmlAdapter實施, LastNameAdapter,EmailAdapter。正如你可以看到每個字段以相似的方式表示 - 字段名稱爲xml元素,字段值爲元素的屬性。是否可以創建「通用」適配器,以便我可以傳輸該字段的名稱,並提取該字段的值?

P.S.我知道MOXy JAXB實現,但我想知道是否可以通過引用JAXB實現。

謝謝!

回答

5

您可以使用XmlAdapter這樣的:

import java.io.*; 
import javax.xml.bind.*; 
import javax.xml.bind.annotation.*; 
import javax.xml.bind.annotation.adapters.*; 

@XmlType 
class Valued { 
    @XmlAttribute(name="value") 
    public String value; 
} 

class ValuedAdapter extends XmlAdapter<Valued, String> { 
    public Valued marshal(String s) { 
     Valued v = new Valued(); 
     v.value = s; 
     return v; 
    } 
    public String unmarshal(Valued v) { 
     return v.value; 
    } 
} 

@XmlRootElement 
class Person { 

    @XmlJavaTypeAdapter(ValuedAdapter.class) 
    @XmlElement 
    String firstName; 

    @XmlJavaTypeAdapter(ValuedAdapter.class) 
    @XmlElement 
    String lastName; 

} 

class SO12928971 { 
    public static void main(String[] args) throws Exception { 
     Person p = new Person(); 
     p.firstName = "John"; 
     p.lastName = "Doe"; 
     JAXBContext jc = JAXBContext.newInstance(Person.class); 
     StringWriter sw = new StringWriter(); 
     jc.createMarshaller().marshal(p, sw); 
     String xml = sw.toString(); 
     System.out.println(xml); 
     StringReader sr = new StringReader(xml); 
     p = (Person)jc.createUnmarshaller().unmarshal(sr); 
     assert "John".equals(p.firstName); 
     assert "Doe".equals(p.lastName); 
    } 
} 

這裏的想法是,XML模式,因此也JAXB具有元素名稱內容類型,儘管許多文件之間有着明顯的區別這兩者之間明確的一一對應。所以在上面的代碼中,類型Valued描述了一些具有value屬性的東西,而不考慮元素名稱。要序列化的成員註釋爲@XmlElement,該註釋中沒有包含名稱。所以他們會生成一個名稱來自成員名稱的元素。 @XmlJavaTypeAdapter註釋將導致序列化程序將這些成員視爲它們的類型爲Valued。這就是他們的XML內容類型。

上面的代碼的模式是這樣的:

<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 

    <xs:element name="person" type="person"/> 

    <xs:complexType name="person"> 
    <xs:sequence> 
     <xs:element name="firstName" type="valued" minOccurs="0"/> 
     <xs:element name="lastName" type="valued" minOccurs="0"/> 
    </xs:sequence> 
    </xs:complexType> 

    <xs:complexType name="valued"> 
    <xs:sequence/> 
    <xs:attribute name="value" type="xs:string"/> 
    </xs:complexType> 
</xs:schema> 
+1

對於「JAXB在元素名稱和內容類型之間有明確的區別」 –

0

注:我是EclipseLink JAXB (MOXy)鉛和JAXB (JSR-222)專家小組的成員。

P.S.我知道MOXY JAXB實現,但我想知道是否可以通過引用JAXB實現來實現 。

爲了進行比較,我添加了如何使用EclipseLink JAXB(MOXy)的@XmlPath擴展名完成此操作。

package forum12928971; 

import javax.xml.bind.annotation.*; 
import org.eclipse.persistence.oxm.annotations.XmlPath; 

@XmlRootElement 
@XmlAccessorType(XmlAccessType.FIELD) 
class Person{ 

    @XmlPath("firstName/@value") 
    String firstName; 

    @XmlPath("lastName/@value") 
    String lastName; 

    @XmlPath("email/@value") 
    String email; 

} 

JAXB。性能

要指定莫西爲您的JAXB提供者,你需要在同一個包添加一個名爲jaxb.properties文件作爲您的域模型如下條目:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 

演示

package forum12928971; 

import java.io.File; 
import javax.xml.bind.*; 

public class Demo { 
    public static void main(String[] args) throws Exception { 
     JAXBContext jc = JAXBContext.newInstance(Person.class); 

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     File xml = new File("src/forum12928971/input.xml"); 
     Person person = (Person) unmarshaller.unmarshal(xml); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(person, System.out); 
    } 

} 

input.xml /輸出

<?xml version="1.0" encoding="UTF-8"?> 
<person> 
    <firstName value="asd"/> 
    <lastName value="bcd"/> 
    <email value="qwe"/> 
</person>