2011-03-24 149 views
5

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

} 

回答

9

元素默认值

得到你需要如下注释它的元素属性的默认值:

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

我发现你正在试图做的是明智的,尤其是有属性与简单的元素和谐的。这似乎很奇怪,但似乎jaxb2实现者选择添加一组额外的扩展,您必须添加一组扩展才能获得所需的行为。请参阅:

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

jaxb2-commons默认值插件指的是一个额外的命令(和罐子)你添加到xjc依次添加默认行为到现场。在我的情况:(其中,当然,有条件的空支票呈现的默认值与否)

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

使用布莱斯Doughan似乎是实际工作中各地。根据XML文档的性质,这可能是完美的。

然而,看起来这个默认值插件可能会将解决方案移到构建过程中,而不会看到代码的变化(假设您使用Dom而不是Sax分析器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> 
1

另一种方式来设置的默认值可以是beforeMarshal(编组的Marshaller)函数:

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