不使用注释的 Java 代码到 XML/XSD

Posted

技术标签:

【中文标题】不使用注释的 Java 代码到 XML/XSD【英文标题】:Java Code to XML/XSD without using Annotation 【发布时间】:2012-07-26 11:18:43 【问题描述】:

我需要将 Java 类编组和解组为 XML。不属于我的类,我无法添加注释以便可以使用 JAXB。

有没有给定约束条件下将 Java 转换为 XML 的好方法?

另外,我认为一个工具可能会有所帮助,但如果有一些 Java API 可以做同样的事情,我会更感兴趣。

【问题讨论】:

【参考方案1】:

注意:我是EclipseLink JAXB (MOXy) 领导,也是JAXB (JSR-222) 专家组的成员。

域模型

我将使用以下域模型来回答这个问题。请注意模型上没有 JAXB 注释。

客户

package forum11693552;

import java.util.*;

public class Customer 

    private String firstName;
    private String lastName;
    private List<PhoneNumber> phoneNumbers = new ArrayList<PhoneNumber>();

    public String getFirstName() 
        return firstName;
    

    public void setFirstName(String firstName) 
        this.firstName = firstName;
    

    public String getLastName() 
        return lastName;
    

    public void setLastName(String lastName) 
        this.lastName = lastName;
    

    public List<PhoneNumber> getPhoneNumbers() 
        return phoneNumbers;
    

    public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) 
        this.phoneNumbers = phoneNumbers;
    


电话号码

package forum11693552;

public class PhoneNumber 

    private String type;
    private String number;

    public String getType() 
        return type;
    

    public void setType(String type) 
        this.type = type;
    

    public String getNumber() 
        return number;
    

    public void setNumber(String number) 
        this.number = number;
    



选项 #1 - 任何 JAXB (JSR-222) 实现

JAXB 是异常配置,这意味着您只需要在您希望映射行为与默认行为不同的地方添加注释。下面是一个示例的链接,该示例演示了如何在没有注释的情况下使用任何 JAXB impl:

演示

package forum11693552;

import javax.xml.bind.*;
import javax.xml.namespace.QName;

public class Demo 

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

        Customer customer = new Customer();
        customer.setFirstName("Jane");
        customer.setLastName("Doe");

        PhoneNumber workPhone = new PhoneNumber();
        workPhone.setType("work");
        workPhone.setNumber("555-1111");
        customer.getPhoneNumbers().add(workPhone);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        JAXBElement<Customer> rootElement = new JAXBElement<Customer>(new QName("customer"), Customer.class, customer);
        marshaller.marshal(rootElement, System.out);
    


输出

<customer>
    <firstName>Jane</firstName>
    <lastName>Doe</lastName>
    <phoneNumbers>
        <number>555-1111</number>
        <type>work</type>
    </phoneNumbers>
</customer>

更多信息

http://wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted/TheBasics

选项 #2 - EclipseLink JAXB (MOXy) 的外部映射文档

如果您确实想自定义映射,那么您可能会对 MOXy 的外部映射文档扩展感兴趣。示例映射文档如下所示:

oxm.xml

<?xml version="1.0"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum11693552">
    <java-types>
        <java-type name="Customer">
            <xml-root-element />
            <java-attributes>
                <xml-element java-attribute="firstName" name="first-name" />
                <xml-element java-attribute="lastName" name="last-name" />
                <xml-element java-attribute="phoneNumbers" name="phone-number" />
            </java-attributes>
        </java-type>
        <java-type name="PhoneNumber">
            <java-attributes>
                <xml-attribute java-attribute="type" />
                <xml-value java-attribute="number" />
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

jaxb.properties

要启用 MOXy 作为您的 JAXB 提供程序,您需要在与域模型相同的包中包含一个名为 jaxb.properties 的文件,并使用以下条目(请参阅:http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html):

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

演示

当使用 EclipseLink MOXy 作为您的 JAXB 提供程序时(请参阅),您可以在引导 @​​987654334@ 时利用外部映射文档

package forum11693552;

import java.util.*;
import javax.xml.bind.*;
import javax.xml.namespace.QName;
import org.eclipse.persistence.jaxb.JAXBContextFactory;

public class Demo 

    public static void main(String[] args) throws Exception 
        Map<String, Object> properties = new HashMap<String,Object>(1);
        properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum11693552/oxm.xml");
        JAXBContext jc = JAXBContext.newInstance(new Class[] Customer.class, properties);

        Customer customer = new Customer();
        customer.setFirstName("Jane");
        customer.setLastName("Doe");

        PhoneNumber workPhone = new PhoneNumber();
        workPhone.setType("work");
        workPhone.setNumber("555-1111");
        customer.getPhoneNumbers().add(workPhone);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        JAXBElement<Customer> rootElement = new JAXBElement<Customer>(new QName("customer"), Customer.class, customer);
        marshaller.marshal(rootElement, System.out);
    


输出

<?xml version="1.0" encoding="UTF-8"?>
<customer>
   <first-name>Jane</first-name>
   <last-name>Doe</last-name>
   <phone-number type="work">555-1111</phone-number>
</customer>

更多信息

http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html http://blog.bdoughan.com/2012/04/extending-jaxb-representing-metadata-as.html

【讨论】:

嗨,你能添加示例代码来解组​​这种方式吗?谢谢。【参考方案2】:

你看过XStream 吗?它将反序列化/反序列化没有注释或 XSD 的标准 POJO。您可以提供自定义来影响元素在 XML 中的显示方式,并且几乎可以开箱即用。

【讨论】:

@JinKwon - 我不知道,但怀疑不是【参考方案3】:

您可以编写自定义XmlAdapter 并使用XmlJavaTypeAdapter 注释来注释受约束类型的字段。基本情况是这样的:

public enum CannotBeAnnotated  value1, value2; 
@XmlRootElement(name="client")
public class ClientClass 
    @XmlJavaTypeAdapter(Bridge.class)
    public CannotBeAnnotated;

@XmlRootElement(name="representation")
public class XmlType 
    @XmlValue
    public String value;

public class Bridge extends XmlAdapter<XmlType, CannotBeAnnotated>
    public XmlType marshal(CannotBeAnnotated c) 
        XmlType x=new XmlType(); 
        x.value=c.name();
        return x;
    
    public CannotBeAnnotated unmarshall(XmlType x) 
        return CannotBeAnnotated.valueOf(x.value);
    

当然,这对于枚举没有用,因为 JAXB 知道如何处理它们。为了简单起见,我只是选择了一个枚举,以便您可以看到这个想法:

    设计一个您控制的 XML 表示 编写将 Java 类型转换为所需类型的适配器 注释“客户端”代码引用所需类型的适配器 利润。

【讨论】:

以上是关于不使用注释的 Java 代码到 XML/XSD的主要内容,如果未能解决你的问题,请参考以下文章

XML XSD 验证中的全局声明错误

Java代码注释

Java中使用注释

如何使用 spark-xml 包使用 XSD 解析 XML?

如何在XML / XSD中定义整数范围?

如何获取java代码中的注释