5

コンポーネントオブジェクトをネストされたXML要素にする代わりに、それらのプロパティが、名前の前にタイプが付いたルート要素の直接の子になるように、オブジェクト階層をマーシャリングするにはどうすればよいですか。

たとえば、次のようになります。

                                                    (A)
public class Customer {

    protected String firstName;
    protected String lastName;
    protected Address address;
}

public class Address {

    protected String street;
    protected String city;
}

通常のJAXBアノテーションを使用すると、次のようになります。

                                                    (B)
<customer>
    <firstName>Juan</firstName>
    <lastName>dela Cruz</lastName>
    <address>
        <street>123 Rizal Avenue</street>
        <city>Manila</city>
    </address>
</customer>

しかし、代わりに、私は同じようにマーシャルする必要があります

                                                    (C)
<customer>
    <firstName>Juan</firstName>
    <lastName>dela Cruz</lastName>
    <address_street>123 Rizal Avenue</address_street>
    <address_city>Manila</address_city>
</customer>

私はすでにこの問題のほとんどにJAXBを使用しているので、私のニーズを解決するためにJAXBの呪文があれば素晴らしいと思います。実際、これらは私の特定の状況にいくつかの制約を提示します。

  1. (A)のJavaクラスは、 (B)のXML構造に対応する既存のスキーマからJAXBによって生成されます。生成されたクラスの変更されたバージョンを維持したくない。
  2. 私は上記のスキーマを所有または維持していません。実際のスキーマは非常に大きく、多くの場合、小さな変更が加えられます。同等のスキーマを考え出し、維持するのは面倒です。また、スキーマの変更に対応するために、JAXBによる自動クラス生成に依存しています。
  3. それが物事を容易にするなら、入れ子は最大1レベルの深さです。この例でAddressは、他の複合型は含まれていません。

@XmlPathMOXyからの注釈を見ていますが、 (C)のようにノード名の前に付ける方法がわかりません。

適切なJAXBアノテーションを提供するいくつかのxjcカスタマイズが私を動かすソリューションを夢見ていますが、これまでの私の検索からはそうは思われません。JAXB以外のソリューションで十分です。

4

6 に答える 6

2

注: 私はEclipseLink JAXB(MOXy)のリーダーであり、JAXB(JSR-222)エキスパートグループのメンバーです。

EclipseLink JAXB(MOXy)の外部マッピングファイルを使用して、オブジェクトモデルに2番目のマッピングを適用し、@XmlPath拡張機能を使用してオブジェクトモデルをフラット化できます。

外部マッピングファイル(oxm.xml)

以下は、モデルクラスが。というパッケージ内にある場合の外部マッピングファイルの外観ですforum11007814

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum11007814"
    xml-accessor-type="FIELD">
    <java-types>
        <java-type name="Customer">
            <xml-root-element/>
            <java-attributes>
                <xml-element java-attribute="address" xml-path="."/>
            </java-attributes>
        </java-type>
        <java-type name="Address">
            <java-attributes>
                <xml-element java-attribute="street" name="address_street"/>
                <xml-element java-attribute="city" name="address_city"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

デモ

以下は、を作成するときにMOXyの外部マッピングファイルを活用する方法を示すコードですJAXBContext

package forum11007814;

import java.io.File;
import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;

public class Demo {

    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String,Object>(1);
        properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum11007814/oxm.xml");
        JAXBContext jc = JAXBContext.newInstance(new Class[] {Customer.class}, properties);

        File xml = new File("src/forum11007814/c.xml");
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Customer customer = (Customer) unmarshaller.unmarshal(xml);

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

}

jaxb.properties

MOXyをJAXBプロバイダーとして指定するにはjaxb.properties、ドメインモデルと同じパッケージで呼び出されるファイルを次のエントリで追加する必要があります。

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

c.xml / Output

<?xml version="1.0" encoding="UTF-8"?>
<customer>
   <firstName>Juan</firstName>
   <lastName>dela Cruz</lastName>
   <address_street>123 Rizal Avenue</address_street>
   <address_city>Manila</address_city>
</customer>
于 2012-06-13T08:56:16.377 に答える
0

XStreamConverterを使用してこれを解決しました。アノテーションをチェックして@XmlType、JAXBBeanが変換されているかどうかを判断します。他のすべてのタイプは、デフォルトのコンバーターを通過します。

JAXB中心のソリューションがあれば良かったのですが、XStreamは説得力のある簡単なソリューションを提供しました。

public class FlatXmlConverter implements Converter {

    private static final Logger log =
            LoggerFactory.getLogger(NvpConverter.class);

    @Override
    public void marshal(Object source, HierarchicalStreamWriter writer,
            MarshallingContext context) {
        Class<? extends Object> sourceClass = source.getClass();
        String prefix = (String) context.get("prefix");
        for (Field field : sourceClass.getDeclaredFields()) {
            if (!field.isAccessible()) {
                field.setAccessible(true);
            }
            String name = field.getName();
            Class<?> type = field.getType();

            try {
                Object value = field.get(source);
                if (value != null) {
                    if (type.isAnnotationPresent(XmlType.class)) {
                        context.put("prefix", name);
                        context.convertAnother(value);
                        context.put("prefix", null);
                    } else {
                        String nodeName;
                        if (prefix == null) {
                            nodeName = name;
                        } else {
                            nodeName = prefix + "_" + name;
                        }

                        writer.startNode(nodeName);
                        context.convertAnother(value);
                        writer.endNode();
                    }
                }
            } catch (IllegalArgumentException ex) {
                log.error("IllegalArgumentException", ex);
            } catch (IllegalAccessException ex) {
                log.error("IllegalAccessException", ex);
            }
        }
    }

    @Override
    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    @SuppressWarnings({"rawtypes", "unchecked"})
    public boolean canConvert(Class type) {
        log.debug("canConvert({})", type);
        return type.isAnnotationPresent(XmlType.class);
    }
}
于 2012-06-14T07:18:23.157 に答える
0

これを行う標準的な方法はないと確信しています。できることは、2つのJavaクラスを作成することです。1つは階層構造で、もう1つはフラット構造で、Javaイントロスペクションを使用してデータを一方から他方にコピーし、2番目を使用してxmlを作成します。

于 2012-06-13T03:58:06.730 に答える
0

注:私はjuffrou-xmlの作成者であり、これを簡単な方法で実行できます。xml-mappingファイルでこれを構成するだけです。

<root-element xml="Customer" type="org.yourpackage.Customer">
  <element property="firstName" />
  <element property="lastName" />
  <element property="address.street" xml="address_street"/>
  <element property="address.city" xml="address_city"/>
</root-element>

<root-element xml="Address" type="org.yourpackage.Address" />

ネストされたBeanをフラットなXML構造にマーシャリングするのは、この方法で簡単です。逆に、マーシャリングを解除すると、期待どおりにオブジェクトグラフが作成されます。

ここでJuffrou-XMLをチェックしてください。

于 2013-05-21T22:26:39.993 に答える
-1

JiBX(XMLデータをJavaオブジェクトにバインドするためのツール)をチェックしましたか? http://jibx.sourceforge.net/binding/tutorial/binding-structures.html

于 2012-06-13T06:44:33.960 に答える
-1

@XmlIDと@XmlIDREFを使用します。そして、すべてのオブジェクトのリストを使用してクラスを作成します。

于 2012-06-14T07:57:53.077 に答える