java JAXB 是否支持默认模式值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5423414/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Does JAXB support default schema values?
提问by Carl S.
I have a schema that defines default values for elements and attributes. I am trying to parse a document using JAXB based on that schema but JAXB is not setting the default values. Any ideas on how to make JAXB honor the default values from the schema?
我有一个定义元素和属性默认值的模式。我正在尝试使用基于该架构的 JAXB 解析文档,但 JAXB 未设置默认值。关于如何让 JAXB 遵守模式中的默认值的任何想法?
example.xsd:
示例.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
示例1.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
根元素.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
子El.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;
}
}
回答by bdoughan
Element Default Value
元素默认值
To get the default value on the element property you need to annotate it as follows:
要获取元素属性的默认值,您需要按如下方式对其进行注释:
@XmlElement(defaultValue="defaultElVal")
public String getChildVal() {
return childVal;
}
Attribute Default Value
属性默认值
If you use EclipseLink JAXB (MOXy)you will get the default attribute value using the code you supplied. There may be a bug in the Metro implementation of JAXB that is preventing this from working. Note I lead the MOXy implementation.
如果您使用EclipseLink JAXB (MOXy),您将使用您提供的代码获得默认属性值。JAXB 的 Metro 实现中可能存在一个错误,导致它无法正常工作。注意我领导 MOXy 实施。
Alternate Approach
替代方法
The following code should work with any JAXB implementation without requiring any code changes to your model. You could do the following and leverage SAXSource:
以下代码应适用于任何 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();
}
}
}
回答by user23969
I find what you're trying to do as sensible, especially to have harmony with Attribute vs. Simple Elements. It seems odd me, but it seems the jaxb2 implementors choose to add an extra set of extensions which you have to add to get the desired behavior. See:
我发现你试图做的事情是明智的,尤其是与 Attribute vs. Simple Elements 保持和谐。我似乎很奇怪,但似乎 jaxb2 实现者选择添加一组额外的扩展,您必须添加这些扩展才能获得所需的行为。看:
(I would have rather seen more natural default behaviors and consistency between Attributes and Elements of at least simple types -- without having to register a plugin. Then provide a plug-in for special cases. My only guys on why this wasn't done was or backwards compatibility--a guess.)
(我宁愿看到至少简单类型的属性和元素之间更自然的默认行为和一致性 - 无需注册插件。然后为特殊情况提供插件。我唯一的人为什么没有这样做是或向后兼容性 - 一个猜测。)
The jaxb2-commons default value plugin refers to an extra commands (and jars) you add to xjc which in turn adds default behaviors to the field. In my case:
jaxb2-commons 默认值插件是指您添加到 xjc 的额外命令(和 jars),它反过来将默认行为添加到该字段。就我而言:
public String getScalarOptionalMaxAndDefaultString() {
if (scalarOptionalMaxAndDefaultString == null) {
return "def val 1";
} else {
return scalarOptionalMaxAndDefaultString;
}
}
(Where, of course, the conditional null check presents the default value or not.)
(当然,条件空检查是否提供默认值。)
Using Blaise Doughan seems like an practical work around. Depending the nature of your XML doc, this may be perfect.
使用 Blaise Doughan 似乎是一项实用的工作。根据您的 XML 文档的性质,这可能是完美的。
Yet, it seems this Default Value plugin might move the solution to the build process and not see a change to your code (assuming you're using a Dom as opposed to Sax parser Blaise suggested).
然而,似乎这个默认值插件可能会将解决方案移至构建过程,而不会看到您的代码发生变化(假设您使用的是 Dom 而不是 Sax 解析器 Blaise 建议的)。
It looks the default-value plugin solve the problem and possibly provide additional extensibility (haven't needed such advanced customization) in the unlikely event you require even more programatic default value control running xjc.
看起来默认值插件解决了这个问题,并可能在不太可能的情况下提供额外的可扩展性(不需要这种高级定制),您需要更多的程序化默认值控制运行 xjc。
Here is a maven config snippet in case it helps:
这是一个 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>
回答by user23969
Another way for setting the default value can be a beforeMarshal(Marshaller marshaller) function:
设置默认值的另一种方法可以是 beforeMarshal(Marshaller marshaller) 函数:
private void beforeMarshal(Marshaller marshaller) {
childVal = (null == getChildVal) ? CHILD_VAL_DEFAULT_VALUE : childVal; }