10

我的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版本不支持它并且我无法控制 Java Container 来更改或修改。

请提出任何形成格式XML良好的解决方案。

4

4 回答 4

15

注意 #1: 我是EclipseLink JAXB (MOXy)负责人和JAXB (JSR-222)专家组的成员。


注意 #2: 您看到的输出与您使用 JAXB 映射的输出相匹配。有关更多信息,请参阅:


将 NULL 表示为空元素

如果要将 null 表示为空元素,有几个选项。

选项 #1 - 使用标准 JAXB API

日期适配器

您可以使用 anXmlAdapter来更改将 的实例Date编组为 XML 的方式。我们将日期转换为一个类的实例,该实例具有一个映射的属性@XmlValue(参见http://blog.bdoughan.com/2011/06/jaxb-and-complex-types-with-simple.html)。JAXB RI 不调用XmlAdapternull 值的机制,因此您将需要使用诸如 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>
于 2012-07-31T20:42:15.500 回答
4

您应该阅读nillable 和 minOccurs XSD 元素属性nil,因为和empty元素之间的区别在XML. iexsi:nil=true类似于SQL NULL但具有空元素表示空元素的存在。:)
我知道这很令人困惑。

要解决您的特定问题,如果您使用JAXB序列化来生成它,我建议您阅读如何使用 JAXB 实例化一个空元素。该问题本身向您展示了如何生成一个空元素。

于 2012-07-31T16:30:15.963 回答
2

布莱斯的回答很好,但已经过时了。有一种更好、更简单的方法可以实现同样的效果。我搜索了许多论坛并结合了不同的解决方案来解决这个问题。我在这里分享,以便对其他人有所帮助。


注意:以下解决方案比日期更普遍。


方法 - 1:如果你想用空字符串替换 xml 中的所有空值

会话事件适配器类

将以下类添加到代码中的方便包中。

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>

方法 - 2:如果您只想用 xml 中的空字符串替换选定的空值

实体类

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

}

输出:

在此输出中,我们看到只有带有 XmlNullPolicy 注释的元素在值为 null 时显示。由于 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>

参考:

  1. 在哪里包含 jaxb.properties 文件?

  2. 将空值表示为 xml jaxb 中的空元素

于 2019-01-11T10:25:24.437 回答
0

我投票赞成gbvb的答案。

我不明白你为什么要这个但是。

xmlns:xsi带有and的空元素xsi:nil是正确的方法。

如果没有这些属性,任何reasonable解析器都会为您提供空字符串even if the element is self-closed

假设您想给客户一个整数值,这意味着许多玩家得分中的最高分。

当您可以计算时,您可以给出正确的值。当还没有球员实际得分时,你应该正确的价值为NULLnil这意味着没有记录累积。

<highestScore among="128">98</highestScore>

可以说最高分是128次尝试中的98次。

<highestScore among="0"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:nil="true"/>

可以说没有最高分是因为没有记录分数。

<highestScore/>

没有任何意义,只是一个简单的自封闭空元素。

于 2012-08-03T12:51:51.227 回答