EclipseLink MOXy:绑定使用与不使用相同的XPath

EclipseLink MOXy:绑定使用与不使用相同的XPath,xpath,binding,jaxb,eclipselink,moxy,Xpath,Binding,Jaxb,Eclipselink,Moxy,输入: 绑定: <?xml version="1.0" encoding="UTF-8"?> <foo:root xmlns:foo="http://www.domain.org/foo" xmlns="http://www.domain.org/foo" xmlns:xsd="http://www.w3.org/2001/XMLSchema#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-i

输入:


绑定:

<?xml version="1.0" encoding="UTF-8"?>
<foo:root xmlns:foo="http://www.domain.org/foo" 
      xmlns="http://www.domain.org/foo"
      xmlns:xsd="http://www.w3.org/2001/XMLSchema#"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <a xsi:type="foo:someType">
   <b  text="some text" />
  </a>
</foo:root>

包测试中的类:

<?xml version="1.0"?>
<xml-bindings
   xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
   package-name="test">

<xml-schema element-form-default="QUALIFIED" namespace="http://www.domain.org/foo">
    <xml-ns prefix="foo" namespace-uri="http://www.domain.org/foo" />
</xml-schema>

 <java-types>        
    <java-type name="Root">
        <xml-root-element name="root"/>
        <java-attributes>
            <xml-element java-attribute="contentRoot" xml-path="." type="test.ContentRoot" />
        </java-attributes>
    </java-type>

    <java-type name="ContentRoot">
        <java-attributes>
            <xml-element java-attribute="text" xml-path="a/b/@text" />
            <xml-element java-attribute="contents" xml-path="a/b" type="test.Content" container-type="java.util.List" />
        </java-attributes>
    </java-type>

    <java-type name="Content">
        <java-attributes>
            <xml-element java-attribute="text" xml-path="@text" />
        </java-attributes>
    </java-type>
</java-types>

</xml-bindings>
公共类根目录{
私有列表contentroot=newlinkedlist();
公共列表getContentRoots(){
返回contentroot;
} 
public void setContentRoots(列出contentRoots){
this.contentRoots=contentRoots;
}
public void setContentRoot(ContentRoot ContentRoot){
this.contentRoot.add(contentRoot);
}
}
公共类ContentRoot{
私有列表内容;
私有字符串文本;
公共列表getContents(){
返回内容;
}
公共内容(列表内容){
this.contents=目录;
}
公共字符串getText(){
返回文本;
}
公共void setText(字符串文本){
this.text=文本;
}  
}
公开课内容{
私有字符串文本;
公共字符串getText(){
返回文本;
}
公共void setText(字符串文本){
this.text=文本;
}
}
运行代码:

public class Root {
 private List<ContentRoot> contentRoots = new LinkedList<ContentRoot>();
 public List<ContentRoot> getContentRoots() {
    return contentRoots;
 } 
 public void setContentRoots(List<ContentRoot> contentRoots) {
    this.contentRoots = contentRoots;
 }
 public void setContentRoot(ContentRoot contentRoot) {
    this.contentRoots.add(contentRoot);
 }
}

public class ContentRoot {
 private List<Content> contents;
 private String text;
 public List<Content> getContents() {
    return contents;
 }
 public void setContents(List<Content> contents) {
    this.contents = contents;
 }
 public String getText() {
    return text;
 }
 public void setText(String text) {
    this.text = text;
 }  
}

public class Content  {
 private String text;
 public String getText() {
    return text;
 }
 public void setText(String text) {
    this.text = text;
 }
}
Map jaxbContextProperties=newhashmap(1);
put(jaxbContextProperties.OXM_元数据_源,“bindings.xml”);
JAXBContext JAXBContext=JAXBContextFactory.createContext(新类[]{Root.Class},jaxbContextProperties);
Unmarshaller Unmarshaller=jaxbContext.createUnmarshaller();
Root=(Root)unmarshaller.unmarshal(新文件(“input.xml”);
System.out.println(root.getContentRoots().get(0.getText());
System.out.println(root.getContentRoots().get(0.getContents().get(0.getText());

结果是,文本在ContentRoot中设置,而不是在Content中设置(我从上一个System.out.println()中获得了一个NullPointerException)。有人能告诉我为什么吗?

有几件事让你大吃一惊:

问题1-
ContentRoot
包含无效映射 不允许以下映射组合。对于第二个
xml元素
,您告诉MOXy将
内容
属性映射到元素
a
中出现的重复元素
b
。对于第一个
xml元素
,您试图将可能存在的多个
b
元素之一的文本属性映射到
字符串
属性
文本


映射
text
属性的正确位置在您已经拥有的
Content
类上。我将使用
xml属性
映射并指定
名称
,而不是使用
xml元素
映射,使
xml路径
指向属性(这会起作用)

Map<String, Object> jaxbContextProperties = new HashMap<String, Object>(1);
jaxbContextProperties.put(JAXBContextProperties.OXM_METADATA_SOURCE, "bindings.xml");
JAXBContext jaxbContext = JAXBContextFactory.createContext(new Class[] {Root.class}, jaxbContextProperties);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Root root = (Root)unmarshaller.unmarshal(new File("input.xml"));
System.out.println(root.getContentRoots().get(0).getText());    
System.out.println(root.getContentRoots().get(0).getContents().get(0).getText());
指定
xml路径时
需要包含前缀以获得正确的命名空间限定


更多信息

或者,您可以使用
xml元素包装器映射它,如下所示:


问题#3-
xml path=“.”
不能用于集合属性 目前,MOXy要求集合中的每个项对应于它自己的元素。这意味着此时不能为集合属性指定自XPath


完整示例 您的演示代码似乎与您的域模型不完全匹配。下面是一个完整的示例,它将所有内容结合在一起:

根目录

封装测试;
公共类根{
私有ContentRoot ContentRoot;
公共ContentRoot getContentRoot(){
返回contentRoot;
}
public void setContentRoot(ContentRoot ContentRoot){
this.contentRoot=contentRoot;
}
}
ContentRoot

封装测试;
导入java.util.List;
公共类ContentRoot{
私有列表内容;
公共列表getContents(){
返回内容;
}
公共内容(列表内容){
this.contents=目录;
}
}
内容

封装测试;
公开课内容{
私有字符串文本;
公共字符串getText(){
返回文本;
}
公共void setText(字符串文本){
this.text=文本;
}
}
bindings.xml


演示

封装测试;
导入java.io.File;
导入java.util.*;
导入javax.xml.bind.*;
导入org.eclipse.persistence.jaxb.JAXBContextFactory;
导入org.eclipse.persistence.jaxb.JAXBContextProperties;
公开课演示{
公共静态void main(字符串[]args)引发异常{
Map jaxbContextProperties=newhashmap(1);
put(jaxbContextProperties.OXM_METADATA_源代码,“test/bindings.xml”);
JAXBContext JAXBContext=JAXBContextFactory.createContext(新类[]{Root.Class},jaxbContextProperties);
Unmarshaller Unmarshaller=jaxbContext.createUnmarshaller();
Root=(Root)unmarshaller.unmarshal(新文件(“src/test/input.xml”);
System.out.println(root.getContentRoot().getContents().get(0.getText());
Marshaller=jaxbContext.createMarshaller();
setProperty(marshaller.JAXB_格式化的_输出,true);
marshaller.marshall(root,System.out);
}
}

有几件事让你大吃一惊:

问题1-
ContentRoot
包含无效映射 不允许以下映射组合。对于第二个
xml元素
,您告诉MOXy将
内容
属性映射到
<java-type name="Content">
    <java-attributes>
        <xml-attribute java-attribute="text"/>
    </java-attributes>
</java-type>