一个JAXB Nuance:字符串与枚举(受限制的XSD字符串)

尽管用于XML绑定的Java体系结构JAXB )在名义情况下(尤其是自Java SE 6以来) 相当容易使用,但它也存在许多细微差别。 一些常见的细微差别是由于无法 XML模式定义 (XSD)类型与Java 类型精确匹配绑定 )。 这篇文章看一个具体的例子,它还演示了当JAXB编译器生成Java类时,实施相同XML结构的不同XSD构造如何导致不同的Java类型。

下一个代码清单(用于Food.xsd )定义了食物类型的架构。 XSD要求有效的XML将具有一个称为“食物”的根元素,该元素具有三个嵌套元素“蔬菜”,“水果”和“甜点”。 尽管用于指定“ Vegetable”和“ Dessert”元素的方法与用于指定“ Fruit”元素的方法不同,但是两种方法都导致相似的“有效XML”。 “ Vegetable”和“ Dessert”元素直接声明为稍后在XSD中定义的指定simpleType的元素。 “水果”元素是通过引用( ref= )定义到另一个包含simpleType定义元素的。

Food.xsd

<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:dustin="http://marxsoftware.blogspot.com/foodxml"
           targetNamespace="http://marxsoftware.blogspot.com/foodxml"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified">

   <xs:element name="Food">
      <xs:complexType>
         <xs:sequence>
            <xs:element name="Vegetable" type="dustin:Vegetable" />
            <xs:element ref="dustin:Fruit" />
            <xs:element name="Dessert" type="dustin:Dessert" />
         </xs:sequence>
      </xs:complexType>
   </xs:element>

   <!--
        Direct simple type that restricts xs:string will become enum in
        JAXB-generated Java class.
   -->
   <xs:simpleType name="Vegetable">
      <xs:restriction base="xs:string">
         <xs:enumeration value="Carrot"/>
         <xs:enumeration value="Squash"/>
         <xs:enumeration value="Spinach"/>
         <xs:enumeration value="Celery"/>
      </xs:restriction>
   </xs:simpleType>

   <!--
        Simple type that restricts xs:string but is wrapped in xs:element
        (making it an Element rather than a SimpleType) will become Java
        String in JAXB-generated Java class for Elements that reference it.
   -->
   <xs:element name="Fruit">
      <xs:simpleType>
         <xs:restriction base="xs:string">
            <xs:enumeration value="Watermelon"/>
            <xs:enumeration value="Apple"/>
            <xs:enumeration value="Orange"/>
            <xs:enumeration value="Grape"/>
         </xs:restriction>
      </xs:simpleType>
   </xs:element>

   <!--
        Direct simple type that restricts xs:string will become enum in
        JAXB-generated Java class.        
   -->
   <xs:simpleType name="Dessert">
      <xs:restriction base="xs:string">
         <xs:enumeration value="Pie"/>
         <xs:enumeration value="Cake"/>
         <xs:enumeration value="Ice Cream"/>
      </xs:restriction>
   </xs:simpleType>

</xs:schema>

尽管在模式中对Vegetable元素和Dessert元素的定义与对Fruit定义不同,但是生成的有效XML是相同的。 接下来在food1.xml的代码清单中显示一个有效的XML文件。

food1.xml

<?xml version="1.0" encoding="utf-8"?>
<Food xmlns="http://marxsoftware.blogspot.com/foodxml"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <Vegetable>Spinach</Vegetable>
   <Fruit>Watermelon</Fruit>
   <Dessert>Pie</Dessert>
</Food>

此时,我将使用一个简单的Groovy脚本针对上述XSD验证上述XML。 接下来显示此Groovy XML验证脚本的代码( validateXmlAgainstXsd.groovy )。

validateXmlAgainstXsd.groovy

#!/usr/bin/env groovy

// validateXmlAgainstXsd.groovy
//
// Accepts paths/names of two files. The first is the XML file to be validated
// and the second is the XSD against which to validate that XML.

if (args.length < 2)
{
   println "USAGE: groovy validateXmlAgainstXsd.groovy <xmlFile> <xsdFile>"
   System.exit(-1)
}

String xml = args[0]
String xsd = args[1]

import javax.xml.validation.Schema
import javax.xml.validation.SchemaFactory
import javax.xml.validation.Validator

try
{
   SchemaFactory schemaFactory =
      SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI)
   Schema schema = schemaFactory.newSchema(new File(xsd))
   Validator validator = schema.newValidator()
   validator.validate(new javax.xml.transform.stream.StreamSource(xml))
}
catch (Exception exception)
{
   println "\nERROR: Unable to validate ${xml} against ${xsd} due to '${exception}'\n"
   System.exit(-1)
}
println "\nXML file ${xml} validated successfully against ${xsd}.\n"

下一个屏幕快照展示了针对food1.xmlFood.xsd运行上述Groovy XML验证脚本。

food1ValidatedAgainstFoodXsd

到目前为止,本文的目的是展示XSD中的不同方法如何导致相同的XML有效。 尽管这些不同的XSD方法规定了相同的有效XML,但是当使用JAXB生成基于XSD的类时,它们会导致不同的Java类行为。 下一个屏幕快照展示了针对Food.xsd运行JDK提供的JAXB xjc编译器以生成Java类。

xjcOnFoodXsd

上面显示的JAXB生成的输出表明Java类是为“ Vegetable”和“ Dessert”元素创建的,而不是为“ Fruit”元素创建的。 这是因为在XSD中,“蔬菜”和“甜点”的定义与“水果”不同。 下一个代码清单是由xjc编译器生成的Food.java类的。 从中我们可以看到生成的Food.java类引用了针对VegetableDessert特定生成的Java类型,但是仅引用了Fruit的通用Java字符串。

Food.java(由JAXB jxc编译器生成)

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2015.02.11 at 10:17:32 PM MST 
//


package com.blogspot.marxsoftware.foodxml;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * <complexType>
 *   <complexContent>
 *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       <sequence>
 *         <element name="Vegetable" type="{http://marxsoftware.blogspot.com/foodxml}Vegetable"/>
 *         <element ref="{http://marxsoftware.blogspot.com/foodxml}Fruit"/>
 *         <element name="Dessert" type="{http://marxsoftware.blogspot.com/foodxml}Dessert"/>
 *       </sequence>
 *     </restriction>
 *   </complexContent>
 * </complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "vegetable",
    "fruit",
    "dessert"
})
@XmlRootElement(name = "Food")
public class Food {

    @XmlElement(name = "Vegetable", required = true)
    @XmlSchemaType(name = "string")
    protected Vegetable vegetable;
    @XmlElement(name = "Fruit", required = true)
    protected String fruit;
    @XmlElement(name = "Dessert", required = true)
    @XmlSchemaType(name = "string")
    protected Dessert dessert;

    /**
     * Gets the value of the vegetable property.
     * 
     * @return
     *     possible object is
     *     {@link Vegetable }
     *     
     */
    public Vegetable getVegetable() {
        return vegetable;
    }

    /**
     * Sets the value of the vegetable property.
     * 
     * @param value
     *     allowed object is
     *     {@link Vegetable }
     *     
     */
    public void setVegetable(Vegetable value) {
        this.vegetable = value;
    }

    /**
     * Gets the value of the fruit property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getFruit() {
        return fruit;
    }

    /**
     * Sets the value of the fruit property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setFruit(String value) {
        this.fruit = value;
    }

    /**
     * Gets the value of the dessert property.
     * 
     * @return
     *     possible object is
     *     {@link Dessert }
     *     
     */
    public Dessert getDessert() {
        return dessert;
    }

    /**
     * Sets the value of the dessert property.
     * 
     * @param value
     *     allowed object is
     *     {@link Dessert }
     *     
     */
    public void setDessert(Dessert value) {
        this.dessert = value;
    }

}

具有特定的VegetableDessert类的优点是,与一般的Java String相比,它们具有附加的类型安全性。 Vegetable.javaDessert.java实际上都是枚举,因为它们来自XSD中的枚举值。 接下来的两个代码清单中显示了这两个生成的枚举。

Vegetable.java(使用JAXB xjc编译器生成)

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2015.02.11 at 10:17:32 PM MST 
//


package com.blogspot.marxsoftware.foodxml;

import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for Vegetable.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * <p>
 * <pre>
 * <simpleType name="Vegetable">
 *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
 *     <enumeration value="Carrot"/>
 *     <enumeration value="Squash"/>
 *     <enumeration value="Spinach"/>
 *     <enumeration value="Celery"/>
 *   </restriction>
 * </simpleType>
 * </pre>
 * 
 */
@XmlType(name = "Vegetable")
@XmlEnum
public enum Vegetable {

    @XmlEnumValue("Carrot")
    CARROT("Carrot"),
    @XmlEnumValue("Squash")
    SQUASH("Squash"),
    @XmlEnumValue("Spinach")
    SPINACH("Spinach"),
    @XmlEnumValue("Celery")
    CELERY("Celery");
    private final String value;

    Vegetable(String v) {
        value = v;
    }

    public String value() {
        return value;
    }

    public static Vegetable fromValue(String v) {
        for (Vegetable c: Vegetable.values()) {
            if (c.value.equals(v)) {
                return c;
            }
        }
        throw new IllegalArgumentException(v);
    }

}

Dessert.java(使用JAXB xjc编译器生成)

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.8-b130911.1802 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2015.02.11 at 10:17:32 PM MST 
//


package com.blogspot.marxsoftware.foodxml;

import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for Dessert.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * <p>
 * <pre>
 * <simpleType name="Dessert">
 *   <restriction base="{http://www.w3.org/2001/XMLSchema}string">
 *     <enumeration value="Pie"/>
 *     <enumeration value="Cake"/>
 *     <enumeration value="Ice Cream"/>
 *   </restriction>
 * </simpleType>
 * </pre>
 * 
 */
@XmlType(name = "Dessert")
@XmlEnum
public enum Dessert {

    @XmlEnumValue("Pie")
    PIE("Pie"),
    @XmlEnumValue("Cake")
    CAKE("Cake"),
    @XmlEnumValue("Ice Cream")
    ICE_CREAM("Ice Cream");
    private final String value;

    Dessert(String v) {
        value = v;
    }

    public String value() {
        return value;
    }

    public static Dessert fromValue(String v) {
        for (Dessert c: Dessert.values()) {
            if (c.value.equals(v)) {
                return c;
            }
        }
        throw new IllegalArgumentException(v);
    }

}

为XML元素生成枚举可确保只有这些元素的有效值才能用Java表示。

结论

JAXB使将Java映射到XML相对容易,但是由于Java和XML类型之间没有一对一的映射,因此在某些情况下,为特定XSD指定元素生成的Java类型并不明显。 这篇文章显示了两种不同的构建XSD来强制使用相同的基本XML结构的方法如何导致用JAXB xjc编译器生成的Java类产生截然不同的结果。 在本文中显示的示例中,由于类型安全,所以直接在simpleType上声明XSD中的元素以将XSD的string限制为一组特定的枚举值比将元素声明为对其他包装有受限制的字符串枚举值的simpleType的元素的引用更为可取这是在生成枚举而不是使用常规Java String的。

翻译自: https://www.javacodegeeks.com/2015/02/jaxb-nuance-string-versus-enum-enumerated-restricted-xsd-string.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值