Сгенерировать классы Java из файлов .XSD…?

127

У меня есть гигантский файл схемы .XSD QuickBooks SDK, который определяет XML-запросы / ответы, которые я могу отправлять / получать из QuickBooks.

Я хотел бы иметь возможность легко генерировать классы Java из этих файлов .XSD, которые затем можно было бы использовать для маршалинга XML в объекты Java и объектов Java в XML.

Есть простой способ сделать это...?

В идеале во время выполнения не требуется никаких библиотек, внешних по отношению к базовому дистрибутиву Java. Но я гибкий ...

Кейт Палмер мл.
источник
6
Если вам нужна ручная генерация, поместите файл .xsd в свой проект eclipse, щелкните файл правой кнопкой мыши, затем нажмите «сгенерировать»
Джунчэн Лю

Ответы:

121

JAXB делает ТОЧНО то, что вы хотите. Он встроен в JRE / JDK, начиная с версии 1.6.

basszero
источник
7
К сожалению, эта функциональность больше не будет доступна в Java 9. Это связано с тем, что задействованные классы (в частности, классы com.sun.tools.xjc. *) Больше не будут доступны через JDK.
Marco
4
Я не думаю, что удаление этого из JDK должно быть проблемой, потому что проект java.net (связанный в ответе), вероятно, останется.
stmoebius
1
Как объясняется здесь , вы можете добавить зависимости в Java 9 с помощью аргумента командной строки или добавить зависимость вручную.
Маттиас Рондж
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

Допустим, у меня есть объект Java Item. Я хочу сериализовать объект 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.

Моя Item.javaготова. Затем я могу продолжить и создать сценарий JAXB для маршалинга 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"));

Полный листинг кода см. В листинге 2 main.java. Будет item.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>Foo</ns1:itemName>
<ns1:price>200</ns1:price>

</ns1:item>

Легко, правда? В качестве альтернативы вы можете направить выходной XML как текстовую строку, поток, Writer, 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>

Затем я могу демаршалировать этот 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;
...

Полный листинг кода см. В листинге 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

Последнее, что я хочу здесь упомянуть, это проверка входящего XML с помощью схемы перед демаршалингом в объект 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
...

Когда я пытаюсь демаршалировать данные 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, а это действительно то, что мне нужно для начала. Есть ли способ сделать это?
Кейт Палмер-младший,
7
К сожалению, блог с JAXB Tutorial отключен.
Луис С.
мы можем легко сделать это с помощью jaxb2-maven-plugin, проверьте этот учебник journaldev.com/1312/…
Pankaj
что сложного в ""% java_home% \ bin \ xjc "-p [ваше пространство имен] [xsd_file] .xsd"?
gorefest
30

Использование Eclipse IDE: -

  1. скопируйте xsd в новый / существующий проект.
  2. Убедитесь, что в пути к классам есть требуемые JAXB JAR. Вы можете скачать его здесь .
  3. Щелкните правой кнопкой мыши файл XSD -> Создать -> Классы JAXB.
Кумар Самбхав
источник
17

Самый простой способ - использовать командную строку. Просто введите каталог вашего .xsd файла:

xjc myFile.xsd.

Итак, java сгенерирует все Pojos.

Crozeta
источник
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

Надеюсь, это поможет :)

neel4soft
источник
1
Это действительно работает с каталогом ресурсов? (src / main / resources / schemas), потому что я продолжаю получать это:No XSD files found. Please check your plugin configuration.
zygimantus
7

Вполне лучший вариант %java_home%\bin\xjc -p [your namespace] [xsd_file].xsd.

У меня также есть вопрос, есть ли у нас возможность провести здесь реверс-инжиниринг. если да, можем ли мы сгенерировать xsd из класса pojo?

Sree
источник
xjc доступен только в java6
sree
7

Если вы не против использования внешней библиотеки, я использовал Castor для этого в прошлом.

Марк Новаковски
источник
Если вы генерируете код с помощью Castor, будут ли эти сгенерированные классы по-прежнему зависеть от Caster? Или я могу перенести эти классы на машину без библиотек Castor, и они все равно будут работать?
Кейт Палмер младший,
Нет, сгенерированные классы не зависят от библиотек Castor.
Дэйв
Есть ли какие-нибудь хорошие учебники по использованию Castor для этого? Это выглядит очень многообещающе ... но Java, мягко говоря, не самый сильный язык для меня. Я не уверен, какие файлы / пакеты Castor мне нужно загрузить и как на самом деле генерировать код ... какие-нибудь пошаговые примеры для новичков?
Кейт Палмер младший,
Ознакомьтесь с документацией по использованию класса Castor SourceGenerator на этой странице: castor.org/sourcegen.html
Марк Новаковски,
2
Похоже, что castor давно мертв ... Ссылки на документы все 404.
Павел Веселов
5

Ограничение JAXB.

Я работал над JAXB, на мой взгляд, это хороший способ работы с данными между объектами XML и Java. Положительные стороны - это проверенная и лучшая производительность и контроль над данными во время выполнения. При правильном использовании встроенных инструментов или скриптов это избавляет от множества усилий по написанию кода.

Я обнаружил, что часть настройки - это не сразу задача, и потратил часы на настройку среды разработки.

Однако я отказался от этого решения из-за глупого ограничения, с которым столкнулся. В моем определении схемы XML (XSD) есть атрибут / элемент с именем «значение», и я должен использовать XSD как есть. Это очень маленькое ограничение вынудило мой шаг привязки XJC завершиться с ошибкой «Значение свойства уже использовано».

Это связано с реализацией JAXB, процесс привязки пытается создать объекты Java из XSD, добавляя несколько атрибутов к каждому классу, и один из них является атрибутом значения. Когда он обработал мой XSD, он пожаловался, что уже существует свойство с таким именем.

ОЗУ
источник
4

Разве XJC от JAXB не является возможным ответом на это? Я пытаюсь добиться того же. Тем не менее, он все еще находится в стадии «попытки». Наткнулся на XJC, поэтому подумал поделиться.

Niks
источник
2

Хорошо известный JAXB

Есть плагин maven который может сделать это за вас на любом этапе сборки, который вы хотите.

Вы можете сделать это обоими способами: xsd <-> Java

Франсуа Вокье
источник
1

Говоря об ограничении JAXB, решением при наличии одного и того же имени для разных атрибутов является добавление встроенных настроек jaxb в xsd:

+

, , обязательные декларации. ,

или внешние настройки ...

Вы можете увидеть дополнительную информацию по адресу : http://jaxb.java.net/tutorial/section_5_3-Overriding-Names.html

Nady
источник