【问题标题】:Null values while un-marshalling XML with namspaces using JAXB使用 JAXB 将带有名称空间的 XML 解组时为空值
【发布时间】:2013-02-21 15:12:01
【问题描述】:

我在使用 JAXB 解组简单 XML(CSDL 的子集)时遇到问题。
过去有人曾试图帮助我 (here),但它已部分起作用,我不知道该怎么办...
请考虑以下 XML:

<edmx:Edmx xmlns:edmx="http://schemas.microsoft.com/ado/2007/06/edmx">
  <edmx:DataServices xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" m:DataServiceVersion="3.0">
    <Schema xmlns:cg="http://schemas.microsoft.com/ado/2006/04/codegeneration" xmlns:sap="http://www.sap.com/Protocols/SAPData" xmlns="http://schemas.microsoft.com/ado/2009/11/edm" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" Namespace="myNS">
    </Schema>
  </edmx:DataServices>
</edmx:Edmx>

据我所知,我有一个 package-info.java 文件,看起来像(在同一个包中):

@XmlSchema(
  namespace="http://schemas.microsoft.com/ado/2007/06/edmx",
  elementFormDefault=XmlNsForm.QUALIFIED,
  xmlns={
          @XmlNs(prefix="edmx", namespaceURI="http://schemas.microsoft.com/ado/2007/06/edmx"),
          @XmlNs(prefix="", namespaceURI="http://schemas.microsoft.com/ado/2009/11/edm"),
          @XmlNs(prefix="m", namespaceURI="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata")                                
  }
)
@XmlAccessorType(XmlAccessType.FIELD)
package com.sap.ndb.studio.rdl.csdlparser.jaxb.objects;

import javax.xml.bind.annotation.*;

另外,我还有以下数据结构:

Edmx.java

package com.sap.ndb.studio.rdl.csdlparser.jaxb.objects;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "Edmx")
public class Edmx {

    @XmlElement(name = "DataServices")
    private DataService dataService;

    public DataService getDataService() {
          return dataService;
    }
}

DataService.java

package com.sap.ndb.studio.rdl.csdlparser.jaxb.objects;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class DataService {

    @XmlElement(name = "Schema")
    private Schema schema;

    @XmlAttribute(name = "DataServiceVersion")
    private double version;

    public Schema getSchema() {
      return schema;
    }
 }

Schema.java

package com.sap.ndb.studio.rdl.csdlparser.jaxb.objects;

@XmlRootElement
public class Schema {
  ....
}

注意:在 Schema.java 中,我有一些与 XML 无关的实现,因此我将其移除(内部逻辑)。

使用 JAXB 对 XML 进行解组后,返回的 Edmx 对象在“模式”和“版本”成员中都包含空值,尽管我在 package-info.java 中提到了所有 xmlns 参数。

任何人? :(

【问题讨论】:

标签: java jaxb unmarshalling


【解决方案1】:

更新

在我对您之前的一个问题的回答中,我提供了此问题中模型的映射。

我已更新此答案以解决您发表的以下评论:

我为什么要声明 'namespace=schemas.microsoft.com/ado/2009/11/edm';在我的@XmlElement 中? 很抱歉很烦人(这是我第一次使用 JAXB),但我 只是会有一个很长的 XML,其中包含许多类似于的 @XmlElement 节点 'Schema',我只想为他们声明命名空间 一次……

您可以通过根据模型类对应的命名空间将模型类组织到不同的包中来减少需要声明命名空间的次数。

命名空间的包 1 http://schemas.microsoft.com/ado/2007/06/edmx

包裹信息

对于每个包,我们将使用@XmlSchema 注释来指定命名空间限定。在这个例子中,我们只需要为这个特定的包指定命名空间。

@XmlSchema(
        namespace="http://schemas.microsoft.com/ado/2007/06/edmx",
        elementFormDefault=XmlNsForm.QUALIFIED,
        xmlns={
                @XmlNs(
                    prefix="edmx", 
                    namespaceURI="http://schemas.microsoft.com/ado/2007/06/edmx"
                ),
        }
)
@XmlAccessorType(XmlAccessType.FIELD)
package forum14875956.edmx;

import javax.xml.bind.annotation.*;

Edmx

Edmx 类对应的XML 元素将根据我们在此包的@XmlSchema 注释上定义的内容进行命名空间限定。

package forum14875956.edmx;

import javax.xml.bind.annotation.*;

@XmlRootElement(name = "Edmx")
public class Edmx {

    @XmlElement(name = "DataServices")
    private DataService dataService;

    public DataService getDataService() {
        return dataService;
    }

}

数据服务

DataService 类包含对对应于不同 XML 命名空间的类的引用。如果Schema 类在同一个包中,我们可以使用@XmlElement 注释来覆盖命名空间限定。由于Schema 在不同的包中,我们可以使用@XmlElementRef 注释。这告诉 JAXB 从为该类配置的根元素中派生元素信息。

package forum14875956.edmx;

import javax.xml.bind.annotation.*;
import forum14875956.schema.Schema;

public class DataService {

    //@XmlElement(namespace="http://schemas.microsoft.com/ado/2009/11/edm", name="Schema")
    @XmlElementRef
    private Schema schema;

    public Schema getSchema() {
        return schema;
    }

}

命名空间的包 2 http://schemas.microsoft.com/ado/2009/11/edm

我们将再次使用@XmlSchema 来声明第二个包的命名空间信息。

包裹信息

@XmlSchema(
        namespace="http://schemas.microsoft.com/ado/2009/11/edm",
        elementFormDefault=XmlNsForm.QUALIFIED,
        xmlns={
                @XmlNs(
                    prefix="", 
                    namespaceURI="http://schemas.microsoft.com/ado/2009/11/edm"
                )
        }
)
@XmlAccessorType(XmlAccessType.FIELD)
package forum14875956.schema;

import javax.xml.bind.annotation.*;

架构

Schema 类中的元素将是其包的 @XmlSchema 注释中基于命名空间限定的命名空间信息。

package forum14875956.schema;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="Schema")
public class Schema {

}

原始答案

您需要在 schema 属性的映射中包含命名空间 URI:

@XmlRootElement
public class DataService {

    @XmlElement(name = "Schema" , namespace="http://schemas.microsoft.com/ado/2009/11/edm")
    private Schema schema;

    @XmlAttribute(name = "DataServiceVersion")
    private double version;

    public Schema getSchema() {
      return schema;
    }
 }

完整示例

不久前,我回答了您的一个问题,提供了该模型的完整映射:

【讨论】:

  • 你给我的例子是真的,但是为什么在 Package-Info.java 中声明带有前缀“m”的“schemas.microsoft.com/ado/2009/11/edm”还不够,就像我们对 Edmx 和 DataService 所做的那样?为什么我应该在我的@XmlElement 中声明'namespace=schemas.microsoft.com/ado/2009/11/edm'?很抱歉很烦人(这是我第一次使用 JAXB),但我将有一个很长的 XML,其中包含许多类似于“Schema”的 @XmlElement 节点,我只想为它们声明一次命名空间......
  • @user1027133 - 基于 @XmlSchema 注释,您的 JAXB 实现将把命名空间 http://schemas.microsoft.com/ado/2007/06/edmx 应用于与该包中没有指定另一个命名空间的类对应的任何元素。您可以进行设置,以便与特定命名空间对应的类位于它们自己的包中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-02
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-29
相关资源
最近更新 更多