6

更新 - 见底部的编辑

IDRefs/keyrefs 似乎在 JAXB 注释中是可能的,但 ref 最终成为元素文本。

我希望 ref 成为元素的属性。

例如,给定这个对象模型:

@XmlType
public class Employee {
    @XmlID
    @XmlAttribute
    String name;
    @XmlAttribute
    int years;
    @XmlAttribute
    String foo;
}

@XmlType
public class Office {
    @XmlAttribute
    String name;
    @XmlElementWrapper
    @XmlElement(name = "employee")
    List<Employee> employees;
}

@XmlRootElement
public class Company {
    @XmlElementWrapper
    @XmlElement(name = "office")
    List<Office> offices;
    @XmlElementWrapper
    @XmlElement(name = "employee")
    List<Employee> employees;
}

我希望外部化的 xml 格式最终看起来像这样:

<company>
    <offices>
        <office name="nyc">
            <employees>
                <!--*** id ref to employee name ***-->
                <employee ref="alice"/>
                <employee ref="bob"/>
            </employees>
        </office>
        <office name="sf">
            <employees>
                <employee ref="connie"/>
                <employee ref="daphne"/>
            </employees>
        </office>
    </offices>
    <employees>
        <!-- *** name is the id *** -->
        <employee name="alice" years="3" foo="bar"/>
        <employee name="bob" years="3" foo="bar"/>
        <employee name="connie" years="3" foo="bar"/>
        <employee name="daphne" years="3" foo="bar"/>
    </employees>
</company>

相反,我能做的最好的就是这个(使用上面在 java 代码中列出的注释):

<company>
    <offices>
        <office name="nyc">
            <employees>
                <employee>alice</employee>
                <employee>bob</employee>
            </employees>
        </office>
        <office name="sf">
            <employees>
                <employee>connie</employee>
                <employee>daphne</employee>
            </employees>
        </office>
    </offices>
    <employees>
        <employee name="alice" years="3" foo="bar"/>
        <employee name="bob" years="3" foo="bar"/>
        <employee name="connie" years="3" foo="bar"/>
        <employee name="daphne" years="3" foo="bar"/>
    </employees>
</company>

有没有办法可以强制 idref 值成为员工的属性,而不是元素正文?我知道我可以使用 XML 模式来做到这一点,但如果可能的话,我想坚持使用注释。

谢谢你。

编辑 下面 Torious 的解决方案几乎可以工作,但在某些情况下它并不完全有效。

如果“offices”元素出现在(在 xml 文件中)office 引用的“employee”元素之前,则解组失败。找不到员工引用,并且 EmployeeRef 包装器有一个空的员工对象。如果“员工”是第一位的,它就会起作用。

这不是什么大问题,但是编组方法会将“办公室”放在首位,因此试图解组刚刚编组的内容会失败。

在 Torious 的回答中编辑 2条评论解决了排序问题。

4

2 回答 2

4

解决方案是使用将 anXmlAdapter包装Employee在新类型实例中的 an EmployeeRef,它指定如何映射 XML id ref:

@XmlType
public class Office {

    @XmlAttribute
    String name;

    @XmlElementWrapper
    @XmlElement(name="employee")
    @XmlJavaTypeAdapter(EmployeeAdapter.class) // (un)wraps Employee
    List<Employee> employees;
}

@XmlType
public class EmployeeRef {

    @XmlIDREF
    @XmlAttribute(name="ref")
    Employee employee;

    public EmployeeRef() {
    }

    public EmployeeRef(Employee employee) {
        this.employee = employee;
    }
}

public class EmployeeAdapter extends XmlAdapter<EmployeeRef, Employee> {

    @Override
    public EmployeeRef marshal(Employee employee) throws Exception {
        return new EmployeeRef(employee);
    }

    @Override
    public Employee unmarshal(EmployeeRef ref) throws Exception {
        return ref.employee;
    }
}

祝你好运。

于 2012-04-14T02:44:44.077 回答
2

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

下面是一个示例,说明如何通过利用@XmlPath注释使用 MOXy 完成此操作。由于一个错误,从 2012 年 5 月 17 日开始,您将需要使用 EclipseLink 2.4.0 夜间标签。此修复程序也已添加到 EclipseLink 2.3.3(从 2012 年 5 月 18 日开始)流中。您可以从以下位置下载夜间标签:

办公室

employees属性上,您可以将@XmlIDREF注释与注释结合使用@XmlPath以获得所需的映射。 @XmlIDREF告诉 JAXB 实现写出外键而不是对象。

package forum10150263;

import java.util.List;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlType
public class Office {
    @XmlAttribute
    String name;

    @XmlPath("employees/employee/@ref")
    @XmlIDREF
    List<Employee> employees;
}

员工

的对应物@XmlIDREF@XmlID@XmlID用于指定对象的主键。

package forum10150263;

import javax.xml.bind.annotation.*;

@XmlType
public class Employee {
    @XmlID
    @XmlAttribute
    String name;

    @XmlAttribute
    int years;

    @XmlAttribute
    String foo;
}

公司

通过该机制引用的每个对象@XmlIDREF也需要被包含关系引用。在此示例中,这是由employees属性完成的。

package forum10150263;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Company {
    @XmlElementWrapper
    @XmlElement(name = "office")
    List<Office> offices;

    @XmlElementWrapper
    @XmlElement(name = "employee")
    List<Employee> employees;
}

jaxb.properties

要将 MOXy 指定为您的 JAXB 提供者,您需要jaxb.properties使用以下条目添加与域模型在同一包中命名的文件(请参阅将EclipseLink MOXy 指定为您的 JAXB 提供者

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

演示

标准 JAXB API 用于解组/编组 XML。

package forum10150263;

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Company.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum10150263/input.xml");
        Company company = (Company) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(company, System.out);
    }

}

输入.xml/输出

<?xml version="1.0" encoding="UTF-8"?>
<company>
   <offices>
      <office name="nyc">
         <employees>
            <employee ref="alice"/>
            <employee ref="bob"/>
         </employees>
      </office>
      <office name="sf">
         <employees>
            <employee ref="connie"/>
            <employee ref="daphne"/>
         </employees>
      </office>
   </offices>
   <employees>
      <employee name="alice" years="3" foo="bar"/>
      <employee name="bob" years="3" foo="bar"/>
      <employee name="connie" years="3" foo="bar"/>
      <employee name="daphne" years="3" foo="bar"/>
   </employees>
</company>

了解更多信息

于 2012-05-17T09:42:14.023 回答