JAXB是否支持默认架构值?

时间:2011-03-24 17:58:07

标签: java xml schema jaxb

我有一个模式,用于定义元素和属性的默认值。我试图使用基于该模式的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;
    }

}

3 个答案:

答案 0 :(得分:11)

元素默认值

要获取element属性的默认值,您需要按如下方式对其进行注释:

@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();
        }
    }
}

答案 1 :(得分:4)

我发现你要做的事情是明智的,特别是与属性与简单元素的和谐。这看起来很奇怪,但似乎jaxb2实现者选择添加一组额外的扩展,您必须添加这些扩展以获得所需的行为。见:

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

jaxb2-commons默认值插件是指您添加到xjc的额外命令(和jar),后者又将默认行为添加到字段中。就我而言:

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

(当然,条件空检查在哪里显示默认值。)

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

然而,看起来这个默认值插件可能会将解决方案移动到构建过程而不会看到对代码的更改(假设您使用的是Dom而不是Blaise解析器Blaise建议的)。

它看起来是默认值插件解决问题,并且可能提供额外的可扩展性(不需要这样的高级自定义),万一你需要更多的程序默认值控制运行xjc。

这是一个maven配置代码段,以防它有用:

  <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>

答案 2 :(得分:1)

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

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