สร้างคลาส Java จากไฟล์. XSD ... ?


127

ฉันมีไฟล์สกีมา QuickBooks SDK .XSD ขนาดมหึมาซึ่งกำหนดคำขอ / การตอบกลับ XML ที่ฉันสามารถส่ง / รับจาก QuickBooks

ฉันต้องการที่จะสามารถสร้างคลาส Java จากไฟล์. XSD เหล่านี้ได้อย่างง่ายดายซึ่งฉันสามารถใช้เพื่อมาร์แชล XML เป็นอ็อบเจ็กต์ Java และอ็อบเจ็กต์ Java เป็น XML

มีวิธีง่ายๆในการทำ ... ?

ตามหลักการแล้วจะไม่ต้องใช้ไลบรารีใด ๆ ภายนอกกับ Java distro พื้นฐานในขณะรันไทม์ แต่ฉันยืดหยุ่น ...


6
หากคุณต้องการสร้างด้วยตนเองให้วางไฟล์. xsd ในโปรเจ็กต์ eclipse ของคุณคลิกขวาที่ไฟล์จากนั้นกด "สร้าง"
Junchen Liu

คำตอบ:


121

JAXBทำในสิ่งที่คุณต้องการอย่างแน่นอน มีอยู่ใน JRE / JDK เริ่มต้นที่ 1.6


7
น่าเสียดายที่ฟังก์ชันนี้จะไม่สามารถใช้งานได้ใน Java 9 อีกต่อไปเนื่องจากคลาสที่เกี่ยวข้อง (โดยเฉพาะคลาส com.sun.tools.xjc. *) จะไม่สามารถใช้งานผ่าน JDK ได้อีกต่อไป
Marco

4
ฉันไม่คิดว่าการลบสิ่งนี้ออกจาก JDK น่าจะเป็นปัญหาเพราะโปรเจ็กต์ java.net (ลิงก์ในคำตอบ) น่าจะยังคงอยู่
stmoebius

1
ตามที่อธิบายไว้ที่นี่คุณสามารถเพิ่มการอ้างอิงใน Java 9 โดยอาร์กิวเมนต์บรรทัดคำสั่งหรือเพิ่มการอ้างอิงด้วยตนเอง
Matthias Ronge

118

หากต้องการขยายความคิดเห็น "ใช้ JAXB" ด้านบน

ใน Windows "%java_home%\bin\xjc" -p [your namespace] [xsd_file].xsd

เช่น, "%java_home%\bin\xjc" -p com.mycompany.quickbooks.obj quickbooks.xsd

รอสักครู่และหากคุณมีไฟล์ XSD ที่มีรูปแบบดีคุณจะได้รับคลาส Java ที่มีรูปแบบดี


3
เยี่ยมมากขอบคุณ! หากต้องการสร้างคลาสระดับบนสุดแทนการห่อหุ้มโปรดดู: stackoverflow.com/questions/13175224/… . และหากนำไปสู่ความขัดแย้งของชื่อคลาสโปรดดู: stackoverflow.com/questions/13414407/…
พรุ่งนี้

38

หากคุณต้องการเริ่มเขียนโค้ด Java เป็น XML และ XML เป็น Java ในเวลาน้อยกว่า 5 นาทีให้ลอง Simple XML Serialization อย่าใช้เวลาหลายชั่วโมงในการเรียนรู้ JAXB API http://simple.sourceforge.net/download/stream/doc/tutorial/tutorial.php

อย่างไรก็ตามหากคุณกระตือรือร้นที่จะเรียนรู้ JAXB จริงๆนี่คือบทช่วยสอนที่ยอดเยี่ยม http://blogs.oracle.com/teera/entry/jaxb_for_simple_java_xml

เนื้อหาของการสอน:

JAXB สำหรับการทำให้เป็นอนุกรม Java-XML อย่างง่าย

มีหลายวิธีในการทำอนุกรม XML ใน Java หากคุณต้องการการควบคุมแบบละเอียดในการแยกวิเคราะห์และการทำให้เป็นอนุกรมคุณสามารถใช้ SAX, DOM หรือ Stax เพื่อประสิทธิภาพที่ดีขึ้น แต่สิ่งที่ฉันมักต้องการทำคือการทำแผนที่อย่างง่ายระหว่าง POJO และ XML อย่างไรก็ตามการสร้างคลาส Java เพื่อทำการแยกวิเคราะห์เหตุการณ์ XML ด้วยตนเองนั้นไม่ใช่เรื่องสำคัญ ฉันเพิ่งพบว่า JAXB เป็นการแมป Java-XML หรือการทำให้เป็นอนุกรมที่สะดวกและรวดเร็ว

JAXB มีคุณสมบัติที่มีประโยชน์มากมายคุณสามารถตรวจสอบการใช้งานอ้างอิงได้ที่นี่ บล็อกของ Kohsukeเป็นแหล่งข้อมูลที่ดีในการเรียนรู้เพิ่มเติมเกี่ยวกับ JAXB สำหรับรายการบล็อกนี้ฉันจะแสดงวิธีการทำซีเรียลไลเซชัน Java-XML อย่างง่ายด้วย JAXB

POJO เป็น XML

สมมติว่าฉันมีวัตถุ Item Java ฉันต้องการทำให้วัตถุ Item เป็นอนุกรมเป็นรูปแบบ XML สิ่งที่ฉันต้องทำก่อนอื่นคือใส่คำอธิบายประกอบ POJO นี้ด้วยคำอธิบายประกอบ XML บางส่วนจากแพ็คเกจ javax.xml.bind.annotation. * ดูรายการรหัส 1 สำหรับ Item.java

จากรหัส

  • @XmlRootElement(name="Item") บ่งชี้ว่าฉันต้องการเป็นองค์ประกอบราก
  • @XmlType(propOrder = {"name", "price"}) ระบุลำดับที่ฉันต้องการให้จัดเรียงองค์ประกอบในเอาต์พุต XML
  • @XmlAttribute(name="id", ...) บ่งชี้ว่า id เป็นแอตทริบิวต์ขององค์ประกอบรูท
  • @XmlElement(....) บ่งชี้ว่าฉันต้องการให้ราคาและชื่อเป็นองค์ประกอบภายในรายการ

ของฉันItem.javaพร้อมแล้ว จากนั้นฉันสามารถสร้างสคริปต์ JAXB สำหรับ marshaling Item ได้

//creating Item data object
Item item = new Item();
item.setId(2);
item.setName("Foo");
item.setPrice(200);
.....

JAXBContext context = JAXBContext.newInstance(item.getClass());
Marshaller marshaller = context.createMarshaller();
//I want to save the output file to item.xml
marshaller.marshal(item, new FileWriter("item.xml"));

สำหรับรหัสที่สมบูรณ์รายการโปรดดูรายชื่อรหัส main.java2 item.xmlไฟล์เอาต์พุต Code Listing 3 ถูกสร้างขึ้น ดูเหมือนว่า:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns1:item ns1:id="2" xmlns:ns1="http://blogs.sun.com/teera/ns/item">

 <ns1:itemName>Foo</ns1:itemName>
<ns1:price>200</ns1:price>

</ns1:item>

ง่ายใช่มั้ย? คุณสามารถเปลี่ยนช่อง XML เอาต์พุตเป็นสตริงข้อความ, สตรีม, นักเขียน, ContentHandler และอื่น ๆ ได้โดยเพียงแค่เปลี่ยนพารามิเตอร์ของวิธีการ marshal (... ) เช่น

...
JAXBContext context = JAXBContext.newInstance(item.getClass());
Marshaller marshaller = context.createMarshaller();
// save xml output to the OutputStream instance
marshaller.marshal(item, <java.io.OutputStream instance>);

...
JAXBContext context = JAXBContext.newInstance(item.getClass());
Marshaller marshaller = context.createMarshaller();
StringWriter sw = new StringWriter();
//save to StringWriter, you can then call sw.toString() to get java.lang.String
marshaller.marshal(item, sw);

XML เป็น POJO

ลองย้อนกลับกระบวนการ สมมติว่าตอนนี้ฉันมีข้อมูลสตริง XML แล้วและฉันต้องการเปลี่ยนเป็นวัตถุ Item.java ข้อมูล XML (รายการรหัส 3) ดูเหมือน

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns1:item ns1:id="2" xmlns:ns1="http://blogs.sun.com/teera/ns/item">
<ns1:itemName>Bar</ns1:itemName>
<ns1:price>80</ns1:price>
</ns1:item>

จากนั้นฉันสามารถ unmarshal โค้ด xml นี้ไปยังวัตถุ Item โดย

...
ByteArrayInputStream xmlContentBytes = new ByteArrayInputStream (xmlContent.getBytes());
JAXBContext context = JAXBContext.newInstance(Item.getClass());
Unmarshaller unmarshaller = context.createUnmarshaller();
//note: setting schema to null will turn validator off
unmarshaller.setSchema(null);
Object xmlObject = Item.getClass().cast(unmarshaller.unmarshal(xmlContentBytes));
return xmlObject;
...

สำหรับรายชื่อโค้ดที่สมบูรณ์โปรดดู Code Listing 2 (main.java) ซอร์ส XML สามารถมาได้หลายรูปแบบทั้งจากสตรีมและไฟล์ ข้อแตกต่างเพียงอย่างเดียวคือพารามิเตอร์วิธีการ:

...
unmarshaller.unmarshal(new File("Item.xml")); // reading from file
...
// inputStream is an instance of java.io.InputStream, reading from stream
unmarshaller.unmarshal(inputStream);

การตรวจสอบความถูกต้องด้วย XML Schema

สิ่งสุดท้ายที่ฉันต้องการจะกล่าวถึงที่นี่คือการตรวจสอบความถูกต้องของอินพุต XML ด้วย schema ก่อนที่จะยกเลิกการแชลแนลกับวัตถุ Java ฉันสร้างไฟล์สกีมา XML ชื่อ item.xsd สำหรับรายการรหัสที่สมบูรณ์โปรดดูรายการรหัส 4 (Item.xsd) ตอนนี้สิ่งที่ฉันต้องทำคือลงทะเบียนสคีมานี้เพื่อตรวจสอบความถูกต้อง

...
Schema schema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
.newSchema(new File("Item.xsd"));
unmarshaller.setSchema(schema); //register item.xsd shcema for validation
...

เมื่อฉันพยายามที่จะ unmarshal ข้อมูล XML ไปยัง POJO หากอินพุต XML ไม่สอดคล้องกับสคีมาข้อยกเว้นจะถูกจับ สำหรับรายชื่อรหัสที่สมบูรณ์โปรดดูรายการรหัส 5 (invalid_item.xml)

javax.xml.bind.UnmarshalException
- with linked exception:
javax.xml.bind.JAXBException caught: null
[org.xml.sax.SAXParseException: cvc-datatype-valid.1.2.1: 'item1' is
                                not a valid value for 'integer'.]

ที่นี่ฉันเปลี่ยนแอตทริบิวต์ "id" เป็นสตริงแทนที่จะเป็นจำนวนเต็ม

หากอินพุต XML ถูกต้องกับสคีมาข้อมูล XML จะถูกแยกออกจากอ็อบเจ็กต์ Item.java สำเร็จ


1
สิ่งนี้ดูมีแนวโน้มมากและง่ายและดีกว่าในการทำงานกับสิ่งที่ฉันต้องการมากกว่าสิ่งที่ใหญ่และซับซ้อนเช่น JAXB ขออภัยฉันไม่เห็นวิธีใด ๆ ในการแปลงไฟล์. XSD เป็น. class ที่มีอยู่ซึ่งเป็นสิ่งที่ฉันต้องเริ่มต้นจริงๆ มีวิธีทำไหม?
Keith Palmer Jr.

7
โชคร้ายที่บล็อกด้วย JAXB Tutorial ออฟไลน์อยู่
Luis C.

เราสามารถทำได้อย่างง่ายดายโดยใช้ jaxb2-maven-plugin ตรวจสอบการสอนนี้journaldev.com/1312/…
Pankaj

ซับซ้อนเกี่ยวกับ ""% java_home% \ bin \ xjc "-p [your namespace] [xsd_file] .xsd" อย่างไร
gorefest

30

การใช้ Eclipse IDE: -

  1. คัดลอก xsd ไปยังโปรเจ็กต์ใหม่ / ที่มีอยู่
  2. ตรวจสอบให้แน่ใจว่าคุณมี JAR ที่ต้องการ JAXB ใน classpath ของคุณ คุณสามารถดาวน์โหลดหนึ่งที่นี่
  3. คลิกขวาที่ไฟล์ XSD -> สร้าง -> คลาส JAXB

17

วิธีที่ง่ายที่สุดคือใช้บรรทัดคำสั่ง เพียงพิมพ์ไดเรกทอรีของไฟล์. xsd ของคุณ:

xjc myFile.xsd.

ดังนั้น java จะสร้าง Pojos ทั้งหมด


14

Maven สามารถใช้เพื่อจุดประสงค์คุณต้องเพิ่มการอ้างอิงและทำความสะอาดแอปพลิเคชันของคุณ คุณจะได้รับคลาสทั้งหมดที่สร้างขึ้นโดยอัตโนมัติในโฟลเดอร์เป้าหมายของคุณ

เพียงแค่คัดลอกจากเป้าหมายไปยังที่ที่ต้องการนี่คือ pom.xml ที่ฉันใช้สร้างคลาสจากไฟล์ xsd:

    <plugin>
     <groupId>org.codehaus.mojo</groupId>
     <artifactId>jaxb2-maven-plugin</artifactId>

     <executions>
      <execution>
       <goals>
        <goal>xjc</goal>
       </goals>
      </execution>
     </executions>
     <configuration>
      <schemaDirectory>src/main/webapp/schemas/</schemaDirectory>
     </configuration>
    </plugin>

   </plugins>
  </pluginManagement>
 </build>
</project>

เพียงวางไฟล์ xsd ของคุณไว้ใต้ "src / main / webapp / schemas /" จากนั้น maven จะพบไฟล์เหล่านั้นในเวลาคอมไพล์

หวังว่านี่จะช่วยคุณได้ข้อมูลเพิ่มเติมสามารถพบได้ที่http://www.beingjavaguys.com/2013/04/create-spring-web-services-using-maven.html

หวังว่ามันจะช่วยได้ :)


1
สิ่งนี้ใช้ได้กับไดเร็กทอรีทรัพยากรหรือไม่ (src / main / resources / schemas) เพราะฉันได้รับสิ่งนี้No XSD files found. Please check your plugin configuration.
เรื่อย ๆ


7

%java_home%\bin\xjc -p [your namespace] [xsd_file].xsdดีตัวเลือกที่ดีที่สุดคือ

ฉันยังมีคำถามว่าเรามีตัวเลือกในการทำวิศวกรรมย้อนกลับที่นี่หรือไม่ ถ้าใช่เราสามารถสร้าง xsd จากคลาส pojo ได้หรือไม่


xjc มีเฉพาะใน java6
sree

7

หากคุณไม่สนใจที่จะใช้ไลบรารีภายนอกฉันเคยใช้Castorในอดีต


หากคุณสร้างโค้ดด้วย Castor คลาสที่สร้างขึ้นเหล่านั้นจะยังคงขึ้นอยู่กับ Caster หลังจากข้อเท็จจริงหรือไม่? หรือฉันสามารถย้ายคลาสเหล่านั้นไปยังเครื่องที่ไม่มีไลบรารี Castor แล้วพวกมันจะยังใช้งานได้?
Keith Palmer Jr.

ไม่คลาสที่สร้างขึ้นไม่ได้ขึ้นอยู่กับไลบรารี Castor
dave

มีคำแนะนำที่ดีเกี่ยวกับวิธีใช้ Castor เพื่อทำสิ่งนี้หรือไม่? มันดูมีแนวโน้มมาก ... แต่ Java เป็นภาษาที่พูดน้อยที่สุดไม่ใช่ภาษาที่แข็งแกร่งที่สุดของฉัน ฉันไม่แน่ใจว่าฉันต้องดาวน์โหลดไฟล์ / แพ็คเกจ Castor อะไรบ้างและจะสร้างโค้ดได้อย่างไร ... ตัวอย่างมือใหม่ทีละขั้นตอนรอบ ๆ ?
Keith Palmer Jr.

ดูเอกสารเกี่ยวกับวิธีใช้คลาส Castor SourceGenerator ในหน้านี้: castor.org/sourcegen.html
Marc Novakowski

2
ดูเหมือนว่าลูกล้อจะตายไปนานแล้ว ... ลิงก์ของเอกสารมีทั้งหมด 404 รายการ
Pawel Veselov

5

ข้อ จำกัด ของ JAXB

ฉันทำงานกับ JAXB ตามความเห็นของฉันมันเป็นวิธีที่ดีในการจัดการกับข้อมูลระหว่างอ็อบเจ็กต์ XML และ Java ด้านบวกได้รับการพิสูจน์แล้วและดีกว่าในด้านประสิทธิภาพและการควบคุมข้อมูลระหว่างรันไทม์ ด้วยการใช้เครื่องมือหรือสคริปต์ที่สร้างขึ้นอย่างดีจะทำให้ต้องใช้ความพยายามในการเขียนโค้ดเป็นจำนวนมาก

ฉันพบว่าส่วนการกำหนดค่าไม่ใช่งานทันทีและใช้เวลาหลายชั่วโมงในการตั้งค่าสภาพแวดล้อมการพัฒนา

อย่างไรก็ตามฉันทิ้งโซลูชันนี้เนื่องจากข้อ จำกัด โง่ ๆ ที่ฉันเผชิญ ข้อกำหนด XML Schema (XSD) ของฉันมีแอตทริบิวต์ / องค์ประกอบที่มีชื่อ "value" และฉันต้องใช้ XSD เหมือนเดิม ข้อ จำกัด เพียงเล็กน้อยนี้บังคับให้ขั้นตอนการผูก XJC ของฉันล้มเหลวด้วยข้อผิดพลาด "คุณสมบัติ 'ค่า' ที่ใช้ไปแล้ว"

เนื่องจากการนำ JAXB ไปใช้กระบวนการผูกพยายามสร้างออบเจ็กต์ Java จาก XSD โดยเพิ่มแอตทริบิวต์สองสามรายการให้กับแต่ละคลาสและหนึ่งในนั้นเป็นแอตทริบิวต์ค่า เมื่อประมวลผล XSD ของฉันมันบ่นว่ามีคุณสมบัติที่มีชื่อนั้นอยู่แล้ว


4

XJC ของ JAXB เป็นคำตอบที่เป็นไปได้หรือไม่? ฉันพยายามที่จะบรรลุสิ่งเดียวกัน ยังคงอยู่ในช่วง "พยายาม" แม้ว่า เจอ XJC เลยคิดจะแชร์



1

เมื่อพูดถึงข้อ จำกัด JAXB วิธีแก้ปัญหาเมื่อมีชื่อเดียวกันสำหรับแอตทริบิวต์ที่แตกต่างกันคือการเพิ่มการปรับแต่ง jaxb แบบอินไลน์ให้กับ xsd:

+

. . การประกาศผลผูกพัน .

หรือการปรับแต่งภายนอก ...

ดูข้อมูลเพิ่มเติมได้ที่: http://jaxb.java.net/tutorial/section_5_3-Overriding-Names.html

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.