JAXB使用xi:include导出到模块化xml文件

时间:2022-03-23 15:02:07

I have two XML files

我有两个XML文件

tree.xml

<tree>
    <xi:include href="fruit.xml" xmlns:xi="http://www.w3.org/2001/XInclude">
        <xi:fallback>
            <fruit/>
        </xi:fallback>
    </xi:include>
</tree>

fruit.xml

<fruit>
     ...
</fruit>

I inherited the code to unmarshall the files, and it returns a single java object. I now need to marshall the single java object back to two files. I realize there are other solutions (i.e. using two objects instead of one, which is an option) but I need to know if its possible to marshall a single object and maintain the xi:include (or reintroduce it) and export to two (or more) xml files.

我继承了解组文件的代码,它返回一个java对象。我现在需要将单个java对象编组回两个文件。我意识到还有其他解决方案(即使用两个对象而不是一个,这是一个选项)但我需要知道是否可以编组单个对象并维护xi:include(或重新引入它)并导出为两个(或者更多)xml文件。

Is this even possible? If so any tips/ideas?

这有可能吗?如果有任何提示/想法?

Thanks

Updates:

I have been researching this (I researched prior to asking). I did find this tutorial http://tutorial.waycoolsearch.com/java/jaxb2.php which appeared to have my answer, but alas when I marshall the file it takes what was two and makes one.

我一直在研究这个(我在询问前研究过)。我确实找到了这个教程http://tutorial.waycoolsearch.com/java/jaxb2.php似乎有我的答案,但唉,当我编辑文件时它需要的是两个并制作一个。

2 个解决方案

#1


3  

Below I'll demonstrate how an XmlAdapter could be used to support both marshalling and unmarshalling for this use case.

下面我将演示如何使用XmlAdapter来支持此用例的编组和解组。

XmlAdapter (IncludeFruitAdapter)

An XmlAdapter could be used for this use case.

XmlAdapter可用于此用例。

import java.io.File;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class IncludeFruitAdapter extends XmlAdapter<IncludeFruitAdapter.Include, Fruit> {

    private JAXBContext jc;
    private String href = "fruit.xml";

    public IncludeFruitAdapter() {
        try {
            jc = JAXBContext.newInstance(Fruit.class);
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }


    public static class Include {

        @XmlAttribute
        public String href;

        @XmlElement(namespace="http://www.w3.org/2001/XInclude")
        public Fallback fallback;

    }

    public static class Fallback {

        @XmlElementRef
        public Fruit value;

    }

    @Override
    public Include marshal(Fruit fruit) throws Exception {
        File xml = new File(href);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(fruit, xml);

        Include include = new Include();
        include.href = href;
        include.fallback = new Fallback();
        include.fallback.value = new Fruit();
        return include;
    }

    @Override
    public Fruit unmarshal(Include include) throws Exception {
        File xml = new File(include.href);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        try {
            return (Fruit) unmarshaller.unmarshal(xml);
        } catch(Exception e) {
            return include.fallback.value;
        }
    }

}

Tree

The @XmlJavaTypeAdapter is used to reference the XmlAdapter.

@XmlJavaTypeAdapter用于引用XmlAdapter。

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Tree {

    @XmlJavaTypeAdapter(IncludeFruitAdapter.class)
    @XmlElement(name="include", namespace="http://www.w3.org/2001/XInclude")
    private Fruit fruit;

}

Fruit

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Fruit {

    private String name;

}

Demo

Below is some demo code you can run to prove that everything works:

下面是一些演示代码,您可以运行以证明一切正常:

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

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("input.xml");
        Tree tree = (Tree) unmarshaller.unmarshal(xml);

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

    }

}

#2


0  

I figured out an answer, at least a work around. I suppose this may be the way to do it.

我找到了答案,至少是一个解决方法。我想这可能是这样做的方法。

I was hoping that JAXB had some kind of method to define a section of an object as an include for marshaling, but I could never find anything.

我希望JAXB有某种方法来定义一个对象的一部分作为编组的包含,但我永远找不到任何东西。

Note: I have one extra hack that I will explain below, I suppose you could do it without but I couldn't get it to work and in the case where someone else needs to do this at least they will know.

注意:我有一个额外的黑客,我将在下面解释,我想你可以做到没有,但我无法让它工作,在其他人需要这样做的情况下,至少他们会知道。

The flow is as follows.

流程如下。

  1. One XML file with XI:Include gets unmarshalled to a java object. This object contains the contents of the 2 files (the parent and include).
  2. 一个包含XI:Include的XML文件被解组为java对象。该对象包含2个文件(父文件和包含文件)的内容。

  3. The object is updated.
  4. 对象已更新。

  5. The object is marshalled back to a single temp file (this is the hack).
  6. 该对象被编组回一个临时文件(这是黑客)。

  7. The single temp file is umarshalled to a DOM document. (I wanted to marshall straight to a DOM document, but I always got an empty DOM document with no exceptions).
  8. 单个临时文件被编组为DOM文档。 (我想直接编写一个DOM文档,但我总是得到一个空的DOM文档,没有例外)。

  9. I then manipulate the DOM document by first removing the node that needs to go into the XI:Include and then insert a new XI:include file.
  10. 然后我通过首先删除需要进入XI的节点来操作DOM文档:Include然后插入一个新的XI:include文件。

  11. Transform the DOM document into an xml file. Note, in my case the content of the XI:include won't change, but I suppose that node could be put in a new document and transformed.
  12. 将DOM文档转换为xml文件。请注意,在我的情况下,XI的内容:include不会改变,但我想这个节点可以放在一个新文档中并进行转换。

I will update with code shortly.

我将很快用代码更新。

Any other ways to solve this?

还有其他解决方法吗?

Thanks, Travis

#1


3  

Below I'll demonstrate how an XmlAdapter could be used to support both marshalling and unmarshalling for this use case.

下面我将演示如何使用XmlAdapter来支持此用例的编组和解组。

XmlAdapter (IncludeFruitAdapter)

An XmlAdapter could be used for this use case.

XmlAdapter可用于此用例。

import java.io.File;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class IncludeFruitAdapter extends XmlAdapter<IncludeFruitAdapter.Include, Fruit> {

    private JAXBContext jc;
    private String href = "fruit.xml";

    public IncludeFruitAdapter() {
        try {
            jc = JAXBContext.newInstance(Fruit.class);
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }


    public static class Include {

        @XmlAttribute
        public String href;

        @XmlElement(namespace="http://www.w3.org/2001/XInclude")
        public Fallback fallback;

    }

    public static class Fallback {

        @XmlElementRef
        public Fruit value;

    }

    @Override
    public Include marshal(Fruit fruit) throws Exception {
        File xml = new File(href);
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(fruit, xml);

        Include include = new Include();
        include.href = href;
        include.fallback = new Fallback();
        include.fallback.value = new Fruit();
        return include;
    }

    @Override
    public Fruit unmarshal(Include include) throws Exception {
        File xml = new File(include.href);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        try {
            return (Fruit) unmarshaller.unmarshal(xml);
        } catch(Exception e) {
            return include.fallback.value;
        }
    }

}

Tree

The @XmlJavaTypeAdapter is used to reference the XmlAdapter.

@XmlJavaTypeAdapter用于引用XmlAdapter。

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Tree {

    @XmlJavaTypeAdapter(IncludeFruitAdapter.class)
    @XmlElement(name="include", namespace="http://www.w3.org/2001/XInclude")
    private Fruit fruit;

}

Fruit

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Fruit {

    private String name;

}

Demo

Below is some demo code you can run to prove that everything works:

下面是一些演示代码,您可以运行以证明一切正常:

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

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("input.xml");
        Tree tree = (Tree) unmarshaller.unmarshal(xml);

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

    }

}

#2


0  

I figured out an answer, at least a work around. I suppose this may be the way to do it.

我找到了答案,至少是一个解决方法。我想这可能是这样做的方法。

I was hoping that JAXB had some kind of method to define a section of an object as an include for marshaling, but I could never find anything.

我希望JAXB有某种方法来定义一个对象的一部分作为编组的包含,但我永远找不到任何东西。

Note: I have one extra hack that I will explain below, I suppose you could do it without but I couldn't get it to work and in the case where someone else needs to do this at least they will know.

注意:我有一个额外的黑客,我将在下面解释,我想你可以做到没有,但我无法让它工作,在其他人需要这样做的情况下,至少他们会知道。

The flow is as follows.

流程如下。

  1. One XML file with XI:Include gets unmarshalled to a java object. This object contains the contents of the 2 files (the parent and include).
  2. 一个包含XI:Include的XML文件被解组为java对象。该对象包含2个文件(父文件和包含文件)的内容。

  3. The object is updated.
  4. 对象已更新。

  5. The object is marshalled back to a single temp file (this is the hack).
  6. 该对象被编组回一个临时文件(这是黑客)。

  7. The single temp file is umarshalled to a DOM document. (I wanted to marshall straight to a DOM document, but I always got an empty DOM document with no exceptions).
  8. 单个临时文件被编组为DOM文档。 (我想直接编写一个DOM文档,但我总是得到一个空的DOM文档,没有例外)。

  9. I then manipulate the DOM document by first removing the node that needs to go into the XI:Include and then insert a new XI:include file.
  10. 然后我通过首先删除需要进入XI的节点来操作DOM文档:Include然后插入一个新的XI:include文件。

  11. Transform the DOM document into an xml file. Note, in my case the content of the XI:include won't change, but I suppose that node could be put in a new document and transformed.
  12. 将DOM文档转换为xml文件。请注意,在我的情况下,XI的内容:include不会改变,但我想这个节点可以放在一个新文档中并进行转换。

I will update with code shortly.

我将很快用代码更新。

Any other ways to solve this?

还有其他解决方法吗?

Thanks, Travis