5

オブジェクトに追加したいサブツリーが 1 つあり、JAXB ですべてを単一のツリーとして (適切なタグを使用して) マーシャリングします。ただし、現在、サブツリーのルート タグは別のオブジェクトのタグに置き換えられています。

残念ながら、ここで元のコードを公開することは許可されていないため、テスト コードで問題を再現しました (これがばかげている場合はご容赦ください)。

アイデアは、次の構造を出力したいということです:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:Root xmlns:ns2="urn:my:foo:bar:1.0" xmlns:ns3="urn:other:foo:bar:1.1">
    <Content>
        <Header>
            <ns3:Leaf/>
        </Header>
    </Content>
</ns2:Root>

しかし、現在、私が得るのはこれだけです:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:Root xmlns:ns2="urn:my:foo:bar:1.0" xmlns:ns3="urn:other:foo:bar:1.1">
    <Content>
        <Header/>
    </Content>
</ns2:Root>

必要なすべてのクラスを生成するために 2 つの XSD があるので、その側では問題ありません (ただし、これらのクラスは生成されるため、変更することはできません)。

2 番目の XML (間違ったもの) を生成するサンプル コードを次に示します。

package foo.bar;

import java.io.OutputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;

public class Test {

    private JAXBContext context;

    public Test() throws JAXBException {
        context = JAXBContext.newInstance(RootElement.class, LeafElement.class);
    }

    @XmlRootElement(name = "Root", namespace = "urn:my:foo:bar:1.0")
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "Root", propOrder = { "content" })
    public static class RootElement {
        @XmlElement(name = "Content")
        protected ContentElement content;

        public ContentElement getContent() {
            return content;
        }

        public void setContent(ContentElement content) {
            this.content = content;
        }
    }

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "Content", propOrder = { "dummy" })
    public static class ContentElement {
        @XmlElement(name = "Header")
        protected Object dummy;

        public Object getDummy() {
            return dummy;
        }

        public void setDummy(Object dummy) {
            this.dummy = dummy;
        }
    }

    @XmlRootElement(name = "Leaf", namespace = "urn:other:foo:bar:1.1")
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "Leaf")
    public static class LeafElement {

    }

    public Node marshal(Object obj) throws JAXBException {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc = null;
        try {
            DocumentBuilder db = dbf.newDocumentBuilder();
            doc = db.newDocument();
        } catch (ParserConfigurationException ex) {
            throw new JAXBException(ex);
        }

        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.marshal(obj, doc);
        return doc.getDocumentElement();
    }

    public void marshal(Object obj, OutputStream stream) throws JAXBException {
        Marshaller m = context.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        m.marshal(obj, stream);
    }

    public void test() throws JAXBException {
        RootElement root = new RootElement();
        ContentElement content = new ContentElement();
        root.setContent(content);
        LeafElement leaf = new LeafElement();
        content.setDummy(marshal(leaf));
        marshal(root, System.out);
    }

    public static void main(String[] args) throws JAXBException {
        new Test().test();
    }

}

そのコードには、3 つの「マーシャリング可能な」クラスがあります。

  1. RootElement
  2. ContentElement
  3. LeafElement.

サンプル コードに示すように、最初の 2 つのクラスは 1 つの XSD (特定の名前空間を持つ) から取得され、最後のクラスは別の XSD (別の名前空間を持つ) から取得されます。

これまでのところ、これを修正するために見つけたdummyのは、ContentElement のように設定され、それ自体が LeafElement を保持する追加のクラスを作成して、JAXB が適切な中間ノードを作成することだけでした。しかし、私はこの解決策が非常に見苦しく、保守性が低く、JAXB がそのようなケースを処理する何らかの方法を持っていることを望んでいました。

さらに情報が必要な場合、または私の質問を再定式化する必要がある場合は、躊躇しないでください。自分の問題を簡単な言葉で説明するのに苦労しています。

制約は次のとおりです。

  • RootElement、ContentElement、または LeafElement を変更できません
  • JAXB以外は使えない
4

1 に答える 1

2

どの要素クラスも変更できない場合は、葉にホルダー オブジェクトを作成する必要があります。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public static class LeafElementHolder {
    @XmlAnyElement
    private Object leaf;

    public Object getLeaf() {
        return leaf;
    }

    public void setLeaf(Object leaf) {
        this.leaf = leaf;
    }
}

このクラスをコンテキストに追加します

public Test() throws JAXBException {
    context = JAXBContext.newInstance(RootElement.class, LeafElement.class, LeafElementHolder.class);
}

これを test() メソッドで使用します

    LeafElement leaf = new LeafElement();
    LeafElementHolder holder = new LeafElementHolder();
    holder.setLeaf(leaf);
    content.setDummy(marshal(holder));

XML には 4 つの要素があるため、Java には 4 つのクラスが必要です。

ns2:Root
  ns2:Content
    ns2:Header
      ns3:Leaf
于 2012-09-23T00:32:50.070 に答える