【问题标题】:JAXB Map with abstract class values具有抽象类值的 JAXB 映射
【发布时间】:2017-06-22 14:59:29
【问题描述】:

我有以下 Map 包含 Double 或 Integer 实例作为值,它们都扩展了抽象类 Number,注释如下:

@XmlElement(name="settings")
private Map<String,Number> settings;

它被编组到 XML 中:

<settings>
    <entry>
        <key>SETTING_A</key>
        <value xsi:type="xs:double">0.03</value>
    </entry>
    <entry>
        <key>SETTING_B</key>
        <value xsi:type="xs:int">1000</value>
    </entry>
</settings>

我还需要为这种类型的 XML 提供 XSD,这就是我遇到问题的地方。我试图用一个选项定义一个 complexType,但它不起作用,因为包含 int 的元素和包含 double 的元素不能具有相同的名称(即它们不能都命名为“value” ),这正是 JAXB 生成的 XML 所做的。

以下 XSD 可以使用,但我不想使用不同的元素名称(或):

<xsd:complexType name="Entry">
    <xsd:sequence>
        <xsd:element name="key" type="NimrodSettingKey" minOccurs="1" maxOccurs="1"/>
        <xsd:choice>
           <xsd:element name="double" type="xsd:double" minOccurs="1" maxOccurs="1"/>
           <xsd:element name="int" type="xsd:integer" minOccurs="1" maxOccurs="1"/>
        </xsd:choice>
    </xsd:sequence>
</xsd:complexType>

关于如何在我的 XSD 文档中指定元素可以是 int 或 double 的任何建议?

谢谢!

编辑#1

@svasa 建议在我的 XSD 中使用以下方法,它为选项中的元素赋予相同的名称:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsd:element name="Settings"/>

<xsd:complexType name="Settings">
   <xsd:sequence>
      <xsd:element name="key" type="xsd:string" minOccurs="1" maxOccurs="1" />
        <xsd:choice>
          <xsd:element name="value" xs:type="xsi:double" minOccurs="1" maxOccurs="1" />
          <xsd:element name="value" xs:type="xsi:integer" minOccurs="1" maxOccurs="1" />
        </xsd:choice>
    </xsd:sequence>
</xsd:complexType>
</xsd:schema>

但我的 XSD 编辑器抱怨此错误:

complex type 'Settings' violates the unique particle attribution rule in its components 'value' and 'value'

我认为这意味着下面的两个元素必须各自具有不同的名称,它们不能都被命名为“值”。

【问题讨论】:

  • the values that contain an int and those that contain a number can't have the same name 是指key 不能与intdouble 同名吗?
  • 是的,例如 key=SETTING_A value=0.5d(双精度)和 key=SETTING_B value=1000(和 int)。

标签: java xml xsd jaxb abstract-class


【解决方案1】:

我最终选择重构我的代码:

@XmlElement(name="settings")
private Map<String,Number> settings

到:

@XmlElementWrapper(name="settings")
@XmlElement(name="setting")
private List<Setting> settings;

我的设置类已重命名为设置,现在存储一个带有属性的设置:

@XmlAttribute(name="name")
private String name;

@XmlAttribute(name="intValue")
private Integer intValue;

@XmlAttribute(name="doubleValue")
private Double doubleValue;

当编组为 XML 时,它会生成具有 doubleValue 或 intValue 属性的元素(但在这两种情况下元素都被命名):

<settings>
   <setting name="SETTING_A" doubleValue="1.0E-5"/>
   <setting name="SETTING_B" intValue="1000"/>
   ...
</settings>

并且生成的XML在XSD包含时有效:

<xsd:complexType name="Settings">
    <xsd:sequence>
        <xsd:element name="setting" type="Setting" minOccurs="0" maxOccurs="unbounded"/>
    </xsd:sequence>
</xsd:complexType>

<xsd:complexType name="Setting">
    <xsd:attribute name="name" type="xsd:string"/>
    <xsd:attribute name="doubleValue" type="xsd:double"/>
    <xsd:attribute name="intValue" type="xsd:int"/>
</xsd:complexType>

【讨论】:

  • 如何解决name double 和 int 相同的问题?
  • @svasa 在最初的问题中,我不想在我的 XSD 中使用不同名称的 XML 元素(即 )。在我自己的回答中,我选择了一个名为 的 XML 元素,它具有名为 doubleValue 和 intValue 的属性(在这种情况下很好)。
【解决方案2】:

xs:choice 应该允许您指定整数或双精度,而maxOccurs="1" 将只处理一个值。

但如果您希望 key 是唯一的,您可以使用 xsd:unique,如下所示:

<xsd:element name="settings">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element maxOccurs="unbounded" name="entry">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="key" type="NimrodSettingKey" minOccurs="1" maxOccurs="1" />
              <xsd:choice>
                <xsd:element name="value" xsi:type="xsd:double" minOccurs="1" maxOccurs="1" />
                <xsd:element name="value" xsi:type="xsd:integer" minOccurs="1" maxOccurs="1" />
              </xsd:choice>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
    <xsd:unique name="keyU">
         <xsd:selector xpath=".//key" />
         <xsd:field xpath="." />
    </xsd:unique>
  </xsd:element>

本节:

<xsd:unique name="keyU">
      <xsd:selector xpath=".//key" />
      <xsd:field xpath="." />
</xsd:unique>

添加一个unique constraint,指定您的keys 应该是唯一的。

【讨论】:

  • 这个解决方案给了我一个错误(参见原始问题 EDIT #1),显然 下的元素不能具有相同的名称(这就是我有在原始帖子中将它们命名为“double”和“int”)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-04
相关资源
最近更新 更多