我的XSD
结构如下所示: -
<element name="XYZDate" maxOccurs="1" minOccurs="1" nillable="true" type="date"/>
当我在此字段中设置空值时,它允许我,但在XML
JAXB
生成<XYZDate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
编组时,它会产生输出
<XYZDate/>
在结果中,我希望输出为XMLStreamWriter
,即不需要架构和其他属性。
我在使用XML
的帮助下摆脱了这一点,但它在单行中产生了完整的XML
。我需要格式化良好的IndentingXMLStreamWriter
格式。
如果我需要使用Java
我的XML
版本不支持它,我无法控制Java容器进行更改或修改。
请建议任何形式{{1}}格式良好的解决方案。
答案 0 :(得分:15)
注意#1:我是EclipseLink JAXB (MOXy)主管,是JAXB (JSR-222)专家组的成员。
注意#2:您看到的输出与您使用JAXB映射的内容相匹配。有关更多信息,请参阅:
将空值表示为空元素
如果要将null表示为空元素,可以使用几个选项。
选项#1 - 使用标准JAXB API
的 DateAdapter 强> 的
您可以使用XmlAdapter
来更改Date
的实例编组为XML的方式。我们将日期转换为具有一个映射为@XmlValue
的属性的类的实例(请参阅http://blog.bdoughan.com/2011/06/jaxb-and-complex-types-with-simple.html)。 JAXB RI不会为XmlAdapter
机制调用空值,因此您需要使用MOXy之类的JAXB impl。
package forum11743306;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.datatype.XMLGregorianCalendar;
public class DateAdapter extends XmlAdapter<DateAdapter.AdaptedDate, XMLGregorianCalendar>{
@Override
public AdaptedDate marshal(XMLGregorianCalendar date) throws Exception {
AdaptedDate adaptedDate = new AdaptedDate();
adaptedDate.value = date;
return adaptedDate;
}
@Override
public XMLGregorianCalendar unmarshal(AdaptedDate adaptedDate) throws Exception {
return adaptedDate.value;
}
public static class AdaptedDate {
@XmlValue
public XMLGregorianCalendar value;
}
}
的根强> 的
使用XmlAdapter
注释引用@XmlJavaTypeAdapter
。
package forum11743306;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.datatype.XMLGregorianCalendar;
@XmlRootElement
public class Root {
private XMLGregorianCalendar xyzDate;
@XmlElement(name = "XYZDate", required=true, nillable = true)
@XmlJavaTypeAdapter(DateAdapter.class)
public XMLGregorianCalendar getXyzDate() {
return xyzDate;
}
public void setXyzDate(XMLGregorianCalendar xyzDate) {
this.xyzDate = xyzDate;
}
}
选项#2 - 使用MOXy的@XmlNullPolicy扩展
MOXy提供@XmlNullPolicy
扩展名,为您提供表示null的灵活性。
package forum11743306;
import javax.xml.bind.annotation.*;
import javax.xml.datatype.XMLGregorianCalendar;
import org.eclipse.persistence.oxm.annotations.*;
@XmlRootElement
public class Root {
private XMLGregorianCalendar xyzDate;
@XmlElement(name = "XYZDate", required=true, nillable = true)
@XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE)
public XMLGregorianCalendar getXyzDate() {
return xyzDate;
}
public void setXyzDate(XMLGregorianCalendar xyzDate) {
this.xyzDate = xyzDate;
}
}
其他档案
以下文件可与任一选项一起使用以完成示例。
的 jaxb.properties 强> 的
要将MOXy指定为JAXB提供程序,您需要在与域模型相同的程序包中包含名为jaxb.properties
的文件,并带有以下条目(请参阅:http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html)。
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
的演示强> 的
package forum11743306;
import javax.xml.bind.*;
import javax.xml.datatype.DatatypeFactory;
import org.eclipse.persistence.Version;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
System.out.println(Version.getVersion());
System.out.println(jc.getClass());
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Root root = new Root();
root.setXyzDate(null);
marshaller.marshal(root, System.out);
root.setXyzDate(DatatypeFactory.newInstance().newXMLGregorianCalendar("2012-08-01"));
marshaller.marshal(root, System.out);
}
}
的输出强> 的
2.4.0
class org.eclipse.persistence.jaxb.JAXBContext
<?xml version="1.0" encoding="UTF-8"?>
<root>
<XYZDate/>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<XYZDate>2012-08-01</XYZDate>
</root>
答案 1 :(得分:3)
您应该阅读nillable and minOccurs XSD element attributes,因为nil
与empty
元素之间的差异在XML
中很重要。即xsi:nil=true
类似于SQL NULL
,但具有空元素表示空元素的呈现。 :)
我知道这很令人困惑。
要解决您的具体问题,如果您使用JAXB
序列化生成该问题,我建议您阅读How to instantiate an empty element with JAXB。问题本身向您展示了如何生成空元素。
答案 2 :(得分:1)
Blaise的回答很好,但是已经过时了。有一种更好,更简单的方法可以实现相同目的。我搜索了很多论坛,并结合了不同的解决方案来实现这一目标。我在这里分享是为了对其他人有帮助。
注意:以下解决方案是比日期更通用的解决方案。
会话事件适配器类
将下面的类添加到代码中的便捷包中。
package com.dev
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping;
import org.eclipse.persistence.oxm.mappings.nullpolicy.XMLNullRepresentationType;
import org.eclipse.persistence.sessions.*;
public class NullPolicySessionEventListener extends SessionEventAdapter {
@Override
public void preLogin(SessionEvent event) {
Project project = event.getSession().getProject();
for(ClassDescriptor descriptor : project.getOrderedDescriptors()) {
for(DatabaseMapping mapping : descriptor.getMappings()) {
if(mapping.isAbstractDirectMapping()) {
XMLDirectMapping xmlDirectMapping = (XMLDirectMapping) mapping;
xmlDirectMapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.EMPTY_NODE);
xmlDirectMapping.getNullPolicy().setNullRepresentedByEmptyNode(true);
}
}
}
}
}
实体类
package com.dev;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
@XmlRootElement(name = "Entity")
public class Entity {
@XmlElement(name = "First_Name", required=true, nillable = true)
private String firstName;
@XmlElement(name = "Last_Name" , required=true, nillable = true)
private String lastName;
public Entity(){}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
DemoApp类
package com.dev;
import javax.xml.bind.*;
import org.eclipse.persistence.*;
import java.util.Map;
import java.util.HashMap;
public class DemoApp {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String,Object>(1);
SessionEventListener sessionEventListener = new NullSessionEventListener();
properties.put(JAXBContextProperties.SESSION_EVENT_LISTENER, sessionEventListener);
JAXBContext context = JAXBContextFactory.createContext(new Class[] {ListofEntities.class, list.get(0).getClass()},properties);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Entity entity = new Entity();
entity.setfirstName(null);
entity.setLastName(null);
marshaller.marshal(entity, System.out);
entity.setfirstName("Ramu");
entity.setLastName("K");
marshaller.marshal(entity, System.out);
}
}
输出:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<First_Name/>
<Last_Name/>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<First_Name>Ramu</First_Name>
<Last_Name>Ramu</Last_Name>
</root>
实体类
package com.dev;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
@XmlRootElement(name = "Entity")
public class Entity {
@XmlElement(name = "First_Name", required=true, nillable = true)
@XmlNullPolicy(emptyNodeRepresentsNull = true, nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE)
private String firstName;
@XmlElement(name = "Last_Name" , required=true, nillable = true)
private String lastName;
public Entity(){}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
DemoApp类
package com.dev;
import javax.xml.bind.*;
import org.eclipse.persistence.*;
public class DemoApp {
public static void main(String[] args) throws Exception {
JAXBContext context = JAXBContextFactory.createContext(new Class[] {ListofEntities.class, list.get(0).getClass()},null);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Entity entity = new Entity();
entity.setfirstName(null);
entity.setLastName(null);
marshaller.marshal(entity, System.out);
entity.setfirstName("Ramu");
entity.setLastName("K");
marshaller.marshal(entity, System.out);
}
}
输出:
在此输出中,当value为null时,仅显示带有XmlNullPolicy批注的元素。由于jaxb的默认行为,省略了另一个元素。
<?xml version="1.0" encoding="UTF-8"?>
<root>
<First_Name/>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
<First_Name>Ramu</First_Name>
<Last_Name>Ramu</Last_Name>
</root>
参考:
答案 3 :(得分:0)
我投了gbvb的答案。
我不明白你为什么要这样,但是。
xmlns:xsi
和xsi:nil
的空元素是正确的方法。
如果没有这些属性,任何reasonable
解析器都会为您提供空字符串even if the element is self-closed
。
假设你想给客户一个整数值,这意味着很多玩家得分最高。
当你可以计算时,你可以给出正确的价值。
当没有玩家实际得分时,您应该将正确的值设为NULL
或nil
,这意味着没有累积记录。
<highestScore among="128">98</highestScore>
可以说最高分为128次尝试中的98次。
和
<highestScore among="0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:nil="true"/>
可以说没有最高分,因为没有记录分数。
但是
<highestScore/>
除了一个简单的自闭空元素外,没有任何意义。