JAXB ยกเลิกการรวมองค์ประกอบ XML หลายรายการไว้ในคลาสเดียว

ฉันมีโครงสร้าง XML ต่อไปนี้ ซึ่งกำลังสร้างโมเดลแนวคิดเดียวในองค์ประกอบ XML หลายรายการ รูปแบบนี้ไม่ได้อยู่ในการควบคุมของฉัน

<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>

ฉันต้องการสร้างแบบจำลองนี้ในฐานข้อมูลที่ฉันควบคุมได้และสามารถมีตาราง Channel ที่เรียบง่ายกว่านี้พร้อมฟิลด์ id, type และ name ดังนั้นฉันอยากจะยกเลิกการแยกเป็น List<Channel> เดี่ยวในคลาส Wrapper

สามารถทำได้ด้วยคำอธิบายประกอบ @Xml... โดยอัตโนมัติหรือไม่ ขณะนี้ฉันกำลังใช้ JAXB เพื่อยกเลิกการแยกรายการคลาส @XmlElement(name="Channel") และ @XmlElement(name="ChannelName") แยกกัน จากนั้นจึงประมวลผลชั่วคราว ChannelName/name บน Channel แต่ฉันคิดว่าจะต้องมีวิธีอัตโนมัติที่ง่ายกว่าในการแมปองค์ประกอบเหล่านี้ หรือเป็นงานของ XSLT?

อาจช่วยได้ถ้ารู้ว่า XML เข้ามาเป็นไฟล์ HTTP ไฟล์ POST และฉันใช้ Spring 3, Java และ Hibernate ฉันหวังว่าบางอย่างใน EclipseLink JAXB (MOXy) อาจช่วยได้ :)


person andyb    schedule 16.03.2011    source แหล่งที่มา


คำตอบ (2)


คุณสามารถประหยัดเวลาในการเขียนโค้ดได้โดยทำให้กระบวนการนี้เป็นอัตโนมัติใน JAXB:

สร้าง XML schema สำหรับ XML ของคุณโดยใช้ลิงก์ด้านล่างเพื่อบันทึกเป็นไฟล์ output.xsd: http://www.xmlforasp.net/CodeBank/System_Xml_Schema/BuildSchema/BuildXMLSchemaaspx

เรียกใช้ไฟล์สคริปต์แบตช์ (ตั้งชื่อเป็น output.bat) ด้านล่างจากโฟลเดอร์รูทโปรเจ็กต์ (.) โดยใช้ JDK เนื่องจากมีเพียง JDK เท่านั้นที่มีเครื่องมือ xjc.exe (กรอกข้อมูลใน รายละเอียดที่จำเป็น):

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

ที่ไหน...

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

ตัวอย่าง:

สมมติว่าโฟลเดอร์โปรเจ็กต์ถูกจัดระเบียบดังนี้:

.
\_src

เรียกใช้คำสั่งต่อไปนี้ที่พรอมต์คำสั่งจาก (.):

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

มันจะสร้างไฟล์บางไฟล์:

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

จากนั้น คุณสามารถสร้างวิธีการที่เป็นประโยชน์สองสามวิธีด้านล่างนี้เพื่อจัดการอ็อบเจ็กต์ 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
สิ่งนี้มีประโยชน์ แต่ฉันไม่คิดว่าจะช่วยแก้ปัญหาของฉันได้ เนื่องจากฉันต้องการเขียนโค้ดให้น้อยที่สุดเท่าที่จะทำได้ แต่ยังปรับเปลี่ยนโครงสร้าง XML ในเวลาผูกด้วย การเขียนโค้ดให้น้อยที่สุดเท่าที่จะเป็นไปได้ไม่ใช่เพราะฉันขี้เกียจ ฉันแค่คิดว่ามันไม่จำเป็น และยังเพิ่มความซับซ้อนและต้องมีการทดสอบที่ครอบคลุมมากขึ้น รหัสที่เรียบง่ายและสง่างามทำให้ฉันมีความสุข อย่างไรก็ตาม +1 สำหรับคำตอบเนื่องจากฉันไม่ทราบลิงก์หรือเครื่องมือที่คุณพูดถึง - person andyb; 17.03.2011
comment
@andyb: บางทีคุณอาจทำการแก้ไขไฟล์ที่สร้างขึ้นโดยอัตโนมัติก่อนและหลังได้ - person eee; 17.03.2011

person    schedule
comment
หวังว่าคุณจะอยู่ใน @Blaise :) ฉันได้ดู XmlPath แล้ว แต่ไม่สามารถหาวิธีค้นหาชื่อสำหรับ ID ที่กำหนดได้ ดังนั้น เมื่อยกเลิกการจัดเรียง Channel แรก XPath ที่ฉันต้องการรับชื่อคือ ChannelName[id="1"]/name แต่ไม่เห็นวิธีเสียบ id เข้า ฉันจะดูบล็อกของคุณตอนนี้ - person andyb; 16.03.2011
comment
@andyb - ขณะนี้เรากำลังดำเนินการเกี่ยวกับคุณลักษณะที่เกี่ยวข้อง (ดู bugs.eclipse.org/339596) . ระยะเริ่มต้นมุ่งเป้าไปที่เงื่อนไขในแอตทริบิวต์ (เช่น ChannelName[@id=1]/Name) คุณจำเป็นต้องจอมพลหรือเพียงแค่ปลดจอมพล? - person bdoughan; 16.03.2011
comment
@Blaise - ฉันแค่ต้องยกเลิกการจัดเรียงและดูเหมือนว่าคุณลักษณะเพรดิเคตอาจเป็นวิธีแก้ปัญหาเนื่องจากฉันต้องดึงข้อมูลจากองค์ประกอบอื่นในเอกสาร นอกจากนี้ ฉันได้ดูบล็อก (ยอดเยี่ยม) ของคุณแล้ว และเกือบจะทำให้ MOXy ทำงานในฤดูใบไม้ผลิแล้ว ฉันใช้เวลาสักครู่เพื่อทำความเข้าใจเกี่ยวกับไฟล์ jaxb.properties และ jaxb.index ขณะนี้ฉันได้รับข้อยกเว้น class org.springframework.oxm.jaxb.Jaxb2Marshaller$ByteArrayDataSource requires a zero argument constructor ฉันใช้บริการ Eclipse Persistence 2.3.0.v20110312-r9123 - person andyb; 16.03.2011
comment
ตกลง ฉันได้แก้ไขข้อผิดพลาดของตัวสร้างอาร์กิวเมนต์เป็นศูนย์แล้ว มันเป็นเพราะความเข้าใจผิดของฉันเกี่ยวกับสิ่งที่ควรอยู่ในไฟล์ jaxb.index และฉันได้ระบุคลาส XMLHelper ของฉันไว้ด้วย! ดู คำแนะนำคำอธิบายประกอบ MOXy Spring JAXB หากใครต้องการทราบตัวอย่างที่ฉัน กำลังติดตาม - person andyb; 16.03.2011
comment
ขอบคุณมากสำหรับ @Blaise นี้ ฉันอยู่ห่างจากรหัสของฉันในขณะนี้ แต่จะลองใช้พรุ่งนี้ ฉันอาจจะเกือบจะถึงจุดนั้นพร้อมกับวิธีแก้ปัญหาเพรดิเคตที่คุณแนะนำ ฉันกำลังวางแผนที่จะเรียกใช้ XML ผ่าน XSLT แบบง่ายก่อนเพื่อเพิ่มแอตทริบิวต์ที่จำเป็นในการเชื่อมโยงองค์ประกอบต่างๆ เข้าด้วยกัน - person andyb; 16.03.2011
comment
XSLT เป็นแนวทางที่ดีที่ผสานรวมกับ JAXB ได้อย่างหมดจด: stackoverflow.com/questions/5112404/ - person bdoughan; 16.03.2011
comment
ขอบคุณสำหรับลิงก์ XSLT และการอัปเดตคำตอบ ฉันสงสัยว่าอาจต้องใช้วัตถุช่วยเหลือบางอย่าง ฉันได้ตัดสินใจใช้ XSLT เพื่อโค้งงอ XML ให้เป็นโครงสร้างที่สวยงามกว่าก่อนการเชื่อมโยง โดยหลักแล้วเนื่องจากฉันรู้จัก XSLT/XPath เป็นอย่างดี แต่ก็ไม่เกี่ยวข้องกับวัตถุพิเศษและซับซ้อนน้อยกว่าด้วย ฉันไม่คิดว่าคุณลักษณะการแมปเพรดิเคต MOXy นั้นเหมาะสมเนื่องจากฉันต้องรวมองค์ประกอบ XML ตามค่าแอตทริบิวต์ของตัวแปรที่ตรงกับเพรดิเคต กล่าวคือ สำหรับ Channel@id=1 I จะต้องค้นหา ChannelName[@id="1"]/Name จากนั้นจึงระบุองค์ประกอบอื่นสำหรับ @id=2 - person andyb; 17.03.2011
comment
ถึงกระนั้น ฉันยังคงใช้ MOXy เนื่องจากฉันชอบคำอธิบายประกอบ @XmlPath จะติดตามพัฒนาการของมันด้วย ฉันคิดว่าฉันกำลังพยายามผูกและจัดระเบียบโครงสร้าง XML แบบแบนๆ ใหม่ในเวลาเดียวกันก็ซับซ้อนเกินไปโดยไม่ต้องใช้วัตถุตัวช่วยหรือการแปลง ฉันคิดว่าฉันสามารถหลีกเลี่ยงคำอธิบายประกอบที่ชาญฉลาดบางอย่างได้ อย่างไรก็ตามขอขอบคุณอีกครั้งและยอมรับคำตอบ :-) - person andyb; 17.03.2011
comment
@andyb - ขณะนี้คุณลักษณะภาคแสดงพร้อมใช้งานแล้ว สำหรับข้อมูลเพิ่มเติม โปรดดูที่: bdoughan.blogspot.com/2011/03/ - person bdoughan; 22.03.2011