【问题标题】:Does JAXB support default schema values?JAXB 是否支持默认模式值?
【发布时间】:2011-07-22 08:36:59
【问题描述】:

我有一个定义元素和属性默认值的模式。我正在尝试基于该架构使用 JAXB 解析文档,但 JAXB 未设置默认值。关于如何使 JAXB 尊重架构中的默认值的任何想法?

example.xsd:

<?xml version="1.0" encoding="UTF-8"?><xs:schemaxmlns:xs="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://www.example.org/example" 
xmlns:tns="http://www.example.org/example">

<xs:element name="root" type="tns:rootType"/>

<xs:complexType name="rootType">
    <xs:sequence>
        <xs:element name="child" type="tns:childType"/>
    </xs:sequence>
</xs:complexType>

<xs:complexType name="childType">
    <xs:sequence>
        <xs:element name="childVal" type="xs:string" default="defaultElVal"/>
    </xs:sequence>
    <xs:attribute name="attr" type="xs:string" default="defaultAttrVal"/>
</xs:complexType>

example1.xml

<?xml version="1.0" encoding="UTF-8"?>
<tns:root xmlns:tns="http://www.example.org/example" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.org/example example.xsd ">
  <child>
    <childVal/>
  </child>
</tns:root>

TestParser.java

package test;  
import java.io.File;  
import javax.xml.XMLConstants;  
import javax.xml.bind.JAXBContext;  
import javax.xml.bind.Unmarshaller;  
import javax.xml.validation.Schema;  
import javax.xml.validation.SchemaFactory;  
public class TestParser {    
    public static void main(String[] pArgs) {  
        try {  
            JAXBContext context = JAXBContext.newInstance(RootElement.class);  
            Unmarshaller unmarshaller = context.createUnmarshaller();  

            SchemaFactory schemaFac = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
            Schema sysConfigSchema = schemaFac.newSchema(
                    new File("example.xsd"));
            unmarshaller.setSchema(sysConfigSchema);
            RootElement root = (RootElement)unmarshaller.unmarshal(
                    new File("example1.xml"));
            System.out.println("Child Val: " + root.getChild().getChildVal());
            System.out.println("Child Attr: " + root.getChild().getAttr());
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }
    }
}

RootElement.java

package test;  
import javax.xml.bind.annotation.XmlRootElement;  

@XmlRootElement(name="root", namespace="http://www.example.org/example")  
public class RootElement {  

    private ChildEl child;  

    public RootElement() {}  

    public ChildEl getChild() {
        return child;
   }

    public void setChild(ChildEl pChild) {
        this.child = pChild;
    }
}

ChildEl.java

package test;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="child")
public class ChildEl {

    private String attr;
    private String childVal;

    public ChildEl() {};

    @XmlAttribute
    public String getAttr() {
        return attr;
    }
    public void setAttr(String pAttr) {
        this.attr = pAttr;
    }

    public String getChildVal() {
        return childVal;
    }
    public void setChildVal(String pVal) {
        this.childVal = pVal;
    }

}

【问题讨论】:

    标签: java xml schema jaxb


    【解决方案1】:

    元素默认值

    要获取元素属性的默认值,您需要如下注释:

    @XmlElement(defaultValue="defaultElVal")
    public String getChildVal() {
        return childVal;
    }
    

    属性默认值

    如果您使用EclipseLink JAXB (MOXy),您将使用您提供的代码获得默认属性值。 JAXB 的 Metro 实现中可能存在一个错误,阻止了它的工作。请注意,我领导 MOXy 实施。


    替代方法

    以下代码应适用于任何 JAXB 实现,而无需对模型进行任何代码更改。您可以执行以下操作并利用 SAXSource:

    import java.io.File;  
    import java.io.FileInputStream;
    
    import javax.xml.XMLConstants;  
    import javax.xml.bind.JAXBContext;  
    import javax.xml.bind.Unmarshaller;  
    import javax.xml.parsers.SAXParserFactory;
    import javax.xml.transform.sax.SAXSource;
    import javax.xml.validation.Schema;  
    import javax.xml.validation.SchemaFactory;  
    
    import org.xml.sax.InputSource;
    import org.xml.sax.XMLReader;
    public class TestParser {    
        public static void main(String[] pArgs) {  
            try {  
                JAXBContext context = JAXBContext.newInstance(RootElement.class);  
                Unmarshaller unmarshaller = context.createUnmarshaller();  
    
                SchemaFactory schemaFac = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
                Schema sysConfigSchema = schemaFac.newSchema(
                        new File("example.xsd"));
    
                SAXParserFactory spf = SAXParserFactory.newInstance();
                spf.setNamespaceAware(true);
                spf.setSchema(sysConfigSchema);
                XMLReader xmlReader = spf.newSAXParser().getXMLReader();
                SAXSource source = new SAXSource(xmlReader, new InputSource(new FileInputStream("example1.xml")));
                RootElement root = (RootElement)unmarshaller.unmarshal(
                        source);
                System.out.println("Child Val: " + root.getChild().getChildVal());
                System.out.println("Child Attr: " + root.getChild().getAttr());
            } catch (Exception e) {
                System.out.println(e.getMessage());
                e.printStackTrace();
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      我发现您尝试做的事情是明智的,尤其是要与属性与简单元素相协调。我似乎很奇怪,但似乎 jaxb2 实现者选择添加一组额外的扩展,您必须添加这些扩展才能获得所需的行为。见:

      (我宁愿看到更自然的默认行为以及至少简单类型的属性和元素之间的一致性——无需注册插件。然后为特殊情况提供插件。我唯一的家伙为什么不这样做是向后兼容性或向后兼容性——猜测。)

      jaxb2-commons 默认值插件是指您添加到 xjc 的额外命令(和 jars),这反过来会向该字段添加默认行为。就我而言:

      public String getScalarOptionalMaxAndDefaultString() {
          if (scalarOptionalMaxAndDefaultString == null) {
              return "def val 1";
          } else {
              return scalarOptionalMaxAndDefaultString;
          }   
      }
      

      (当然,条件空检查是否显示默认值。)

      使用 Blaise Doughan 似乎是一项实用的工作。根据您的 XML 文档的性质,这可能是完美的。

      然而,似乎这个 Default Value 插件可能会将解决方案移至构建过程,并且看不到对代码的更改(假设您使用的是 Dom,而不是 Blaise 建议的 Sax 解析器)。

      看起来默认值插件解决了问题,并且可能提供额外的可扩展性(不需要这种高级定制),以防万一您需要更多程序化的默认值控制运行 xjc。

      这是一个 Maven 配置 sn-p 以防万一:

        <plugin>
          <groupId>org.jvnet.jaxb2.maven2</groupId>
          <artifactId>maven-jaxb2-plugin</artifactId>
          <version>0.8.0</version>
          <executions>
            <execution>
              <phase>generate-sources</phase>
              <goals>
                <goal>generate</goal>
              </goals>
              <configuration>
                  <args>
                      <arg>-Xdefault-value</arg>
                  </args>
                  <plugins>
                      <plugin>
                          <groupId>org.jvnet.jaxb2_commons</groupId>
                          <artifactId>jaxb2-default-value</artifactId>
                          <version>1.1</version>
                      </plugin>
                  </plugins>
              </configuration>
            </execution>
          </executions>
          <configuration><schemaDirectory>src/test/resources</schemaDirectory></configuration>
        </plugin>
      

      【讨论】:

        【解决方案3】:

        另一种设置默认值的方法可以是 beforeMarshal(Marshaller marshaller) 函数:

        private void beforeMarshal(Marshaller marshaller) {
            childVal = (null == getChildVal) ? CHILD_VAL_DEFAULT_VALUE : childVal; }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-11-03
          • 1970-01-01
          • 1970-01-01
          • 2017-07-28
          • 2019-09-06
          • 2012-11-26
          • 2012-12-01
          相关资源
          最近更新 更多