一个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 inJAXB-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 JavaString 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 inJAXB-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.Validatortry {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.xml和Food.xsd運行上述Groovy XML驗證腳本。
到目前為止,本文的目的是展示XSD中的不同方法如何導致相同的XML有效。 盡管這些不同的XSD方法規定了相同的有效XML,但是當使用JAXB生成基于XSD的類時,它們會導致不同的Java類行為。 下一個屏幕快照展示了針對Food.xsd運行JDK提供的JAXB xjc編譯器以生成Java類。
上面顯示的JAXB生成的輸出表明Java類是為“ Vegetable”和“ Dessert”元素創建的,而不是為“ Fruit”元素創建的。 這是因為在XSD中,“蔬菜”和“甜點”的定義與“水果”不同。 下一個代碼清單是由xjc編譯器生成的Food.java類的。 從中我們可以看到生成的Food.java類引用了針對Vegetable和Dessert特定生成的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;}}具有特定的Vegetable和Dessert類的優點是,與一般的Java String相比,它們具有附加的類型安全性。 Vegetable.java和Dessert.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
總結
以上是生活随笔為你收集整理的一个JAXB Nuance:字符串与枚举(受限制的XSD字符串)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何使用Spring Security和
- 下一篇: 金蝶的销售退货怎么处理(金蝶财务软件销售