JAXB memisahkan beberapa elemen XML menjadi satu kelas

Saya memiliki struktur XML berikut, yang memodelkan satu konsep di beberapa elemen XML. Format ini di luar kendali saya.

<Output>
  <Wrapper>
    <Channel>
      <id>1</id>
      <type>x</type>
    </Channel>
    <Channel>
      <id>2</id>
      <type>y</type>
    </Channel>
    <ChannelName>
      <id>1</id>
      <name>Channel name</name>
    </ChannelName>
    <ChannelName>
      <id>2</id>
      <name>Another channel name</name>
    </ChannelName>
  </Wrapper>
</Output>

Saya ingin memodelkan ini dalam database yang saya kendalikan dan dapat memiliki tabel Channel yang lebih sederhana dengan bidang id, type dan name. Oleh karena itu saya ingin memisahkan menjadi satu List<Channel> di kelas Wrapper.

Bisakah ini dilakukan dengan @Xml... anotasi secara otomatis? Saat ini saya menggunakan JAXB untuk memisahkan daftar kelas @XmlElement(name="Channel") dan @XmlElement(name="ChannelName") yang terpisah dan kemudian melakukan pasca-pemrosesan ChannelName/name sementara pada Channel tetapi menurut saya pasti ada cara otomatis yang lebih mudah untuk memetakan elemen-elemen ini. Atau itu pekerjaan untuk XSLT?

Mungkin membantu untuk mengetahui bahwa XML masuk sebagai file HTTP POST dan saya menggunakan Spring 3, Java dan Hibernate. Saya berharap sesuatu di EclipseLink JAXB (MOXy) dapat membantu :)


person andyb    schedule 16.03.2011    source sumber


Jawaban (2)


Anda dapat menghemat waktu pengkodean dengan mengotomatiskan proses ini di JAXB:

Buat skema XML untuk XML Anda menggunakan tautan di bawah ini dan simpan sebagai file output.xsd: http://www.xmlforasp.net/CodeBank/System_Xml_Schema/BuildSchema/BuildXMLSchema.aspx

Jalankan file skrip batch (beri nama output.bat) di bawah ini dari folder akar proyek (.) menggunakan JDK karena hanya JDK yang memiliki alat xjc.exe (isikan rincian yang diperlukan):

"C:\Program Files\Java\jdk1.6.0_24\bin\xjc.exe" -p %1 %2 -d %3

Di mana...

syntax: output.bat %1 %2 %3
%1 = target package name
%2 = full file path name of the generated XML schema .xsd 
%3 = root source folder to store generated JAXB java files

Contoh:

katakanlah folder proyek disusun sebagai berikut:

.
\_src

Jalankan perintah berikut pada prompt perintah dari (.):

output.bat com.project.xml .\output.xsd .\src

Ini akan membuat beberapa file:

.
\_src
  \_com
    \_project
      \_xml
        |_ObjectFactory.java
        |_Output.java

Kemudian, Anda dapat membuat beberapa metode berguna di bawah ini untuk memanipulasi objek Output:

private JAXBContext jaxbContext = null;
private Unmarshaller unmarshaller = null;
private Marshaller marshaller = null;

public OutputManager(String packageName) {
    try {
        jaxbContext = JAXBContext.newInstance(packageName);
        unmarshaller = jaxbContext.createUnmarshaller();
        marshaller = jaxbContext.createMarshaller();
    } catch (JAXBException e) {
    }
}

public Output loadXML(InputStream istrm) {

    Output load = null;

    try {
        Object o = unmarshaller.unmarshal(istrm); 

        if (o != null) {

            load = (Output) o;

        }

    } catch (JAXBException e) {

        JOptionPane.showMessageDialog(null, e.getLocalizedMessage(), e.getClass().getSimpleName(), JOptionPane.ERROR_MESSAGE);

    }
    return load;
}

public void saveXML(Object o, java.io.File file) {

    Output save = null;

    try {
        save = (Output) o;

        if (save != null) {
            marshaller.marshal(save, file);
        }

    } catch (JAXBException e) {

        JOptionPane.showMessageDialog(null, e.getLocalizedMessage(), e.getClass().getSimpleName(), JOptionPane.ERROR_MESSAGE);

    }
}

public void saveXML(Object o, FileOutputStream ostrm) {

    Output save = null;

    try {

        save = (Output) o;

        if (save != null) {
            marshaller.marshal(save, ostrm);
        }

    } catch (JAXBException e) {

        JOptionPane.showMessageDialog(null, e.getLocalizedMessage(), e.getClass().getSimpleName(), JOptionPane.ERROR_MESSAGE);

    }
}
person eee    schedule 16.03.2011
comment
Ini berguna tetapi menurut saya ini tidak akan menyelesaikan masalah saya karena saya benar-benar ingin menulis kode sesedikit mungkin tetapi juga memanipulasi struktur XML pada waktu terikat. Menulis kode sesedikit mungkin bukan karena saya malas, saya hanya menganggapnya tidak perlu dan juga menambah kerumitan serta memerlukan pengujian yang lebih ekstensif. Kode yang sederhana dan elegan membuat saya senang. Namun, beri +1 untuk jawabannya karena saya tidak mengetahui tautan atau alat yang Anda sebutkan. - person andyb; 17.03.2011
comment
@andyb: Mungkin Anda dapat mengotomatisasi terlebih dahulu dan kemudian mengedit file yang dihasilkan. - person eee; 17.03.2011

person    schedule
comment
Berharap Anda berada di @Blaise :) Saya telah melihat XmlPath tetapi tidak tahu cara mencari nama untuk id tertentu. Jadi ketika unmarshalling Channel pertama, XPath saya ingin mengambil namanya adalah ChannelName[id="1"]/name tetapi tidak dapat melihat cara memasang id. Saya akan melihat blog Anda sekarang. - person andyb; 16.03.2011
comment
@andyb - Saat ini kami sedang mengerjakan fitur terkait (lihat bugs.eclipse.org/339596) . Tahap awal ditujukan pada kondisi pada atribut (yaitu Nama Saluran[@id=1]/Nama). Apakah Anda perlu melakukan marshal atau hanya unmarshal? - person bdoughan; 16.03.2011
comment
@Blaise - Saya hanya perlu melakukan unmarshal dan sepertinya fitur predikat mungkin menjadi solusinya karena saya perlu mengambil data dari elemen di tempat lain dalam dokumen? Juga, saya telah melihat blog Anda (luar biasa) dan hampir membuat MOXy berfungsi di Musim Semi. Butuh beberapa saat bagi saya untuk memahami tentang file jaxb.properties dan jaxb.index. Saat ini saya mendapatkan pengecualian class org.springframework.oxm.jaxb.Jaxb2Marshaller$ByteArrayDataSource requires a zero argument constructor. Saya menggunakan Layanan Persistensi Eclipse 2.3.0.v20110312-r9123 - person andyb; 16.03.2011
comment
Oke, jadi saya telah memecahkan kesalahan konstruktor argumen nol. Itu karena kesalahpahaman saya tentang apa yang harus ada di file jaxb.index dan saya telah mendaftarkan kelas XMLHelper saya juga! Lihat Panduan Anotasi MOXy Spring JAXB jika ada yang ingin mengetahui contoh saya mengikuti. - person andyb; 16.03.2011
comment
Terima kasih banyak untuk @Blaise ini. Saya jauh dari kode saya saat ini tetapi akan mencobanya besok. Saya mungkin hampir sampai dengan solusi predikat yang Anda sarankan. Saya berencana menjalankan XML melalui XSLT sederhana terlebih dahulu untuk menambahkan atribut yang diperlukan untuk menghubungkan elemen bersama-sama. - person andyb; 16.03.2011
comment
XSLT adalah pendekatan bagus yang terintegrasi secara rapi dengan JAXB: stackoverflow.com/questions/5112404/ - person bdoughan; 16.03.2011
comment
Terima kasih atas tautan XSLT dan pembaruan jawabannya. Saya curiga itu mungkin memerlukan beberapa objek pembantu. Saya telah memutuskan untuk menggunakan XSLT untuk membengkokkan XML menjadi struktur yang lebih bagus sebelum mengikat, terutama karena saya mengetahui XSLT/XPath dengan baik tetapi juga tidak melibatkan objek tambahan dan tidak terlalu rumit. Menurut saya fitur pemetaan predikat MOXy tidak cocok karena saya perlu menggabungkan elemen XML berdasarkan nilai atribut variabel yang cocok dengan predikatnya. yaitu Untuk Channel@id=1 I perlu menemukan ChannelName[@id="1"]/Name dan kemudian elemen berbeda untuk @id=2 - person andyb; 17.03.2011
comment
Meskipun demikian, saya masih akan menggunakan MOXy karena saya menyukai anotasi @XmlPath. Saya juga akan mengikuti perkembangannya. Saya hanya berpikir saya mencoba untuk mengikat dan mengatur ulang struktur XML yang sangat datar pada saat yang sama terlalu rumit tanpa menggunakan objek pembantu atau transformasi. Saya pikir saya bisa mendapatkan beberapa penjelasan yang sangat cerdas. Bagaimanapun, terima kasih sekali lagi dan jawaban diterima :-) - person andyb; 17.03.2011
comment
@andyb - Fitur predikat sekarang tersedia, untuk informasi lebih lanjut lihat: bdoughan.blogspot.com/2011/03/ - person bdoughan; 22.03.2011