Мы используем xjc для генерации Java-классов JAXB для генерации XML.Все работает отлично, за исключением того, что мы попытались настроить сгенерированные префиксы пространства имен , как описано здесь .Мы застряли с «решением 2», настраивая package-info.java, из-за используемой версии JAXB.
Структура, которую мы имеем, имеет несколько глубинных импортов: корневое пространство имен импортирует другое пространство имен, которое вочередь импортирует еще третий.
MCVE xsds
root.xsd (импортирует other.xsd):
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="root" xmlns:other="other" targetNamespace="root" version="1.0">
<xs:import namespace="other" schemaLocation="other.xsd" />
<xs:element name="rootElem">
<xs:complexType>
<xs:choice>
<xs:element ref="rootElem1"/>
</xs:choice>
</xs:complexType>
</xs:element>
<xs:element name="rootElem1" nillable="false">
<xs:complexType>
<xs:sequence>
<xs:element name="data">
<xs:complexType>
<xs:choice>
<xs:element ref="other:otherElem"/>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
other.xsd (импортирует третье.xsd):
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:other="other" xmlns:third="third" targetNamespace="other" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.0">
<xsd:import namespace="third" schemaLocation="third.xsd" />
<xsd:element name="otherElem">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="third:thirdElem" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
third.xsd:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:third="third" targetNamespace="third" elementFormDefault="qualified" attributeFormDefault="unqualified" version="1.0">
<xsd:element name="thirdElem">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="thirdData" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
С этим
Простой тестовый пример
@Test
public void test() throws JAXBException
{
Marshaller marshaller = JAXBContext.newInstance("test.jaxb.generated").createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.example.com/schema.xsd");
RootElem root = new RootElem();
RootElem1 root1 = new RootElem1();
Data d = new Data();
OtherElem other = new OtherElem();
ThirdElem thirdElem = new ThirdElem();
thirdElem.setThirdData("third");
other.setThirdElem(thirdElem);
d.setOtherElem(other);
root1.setData(d);
root.setRootElem1(root1);
Path path = Paths.get("target", "outfile.xml");
Result result = new StreamResult(path.toFile());
marshaller.marshal(root, result);
}
это приводит кэто
сгенерированный XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns4:rootElem xmlns:ns2="other" xmlns:ns3="third" xmlns:ns4="root" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/schema.xsd">
<ns4:rootElem1>
<data>
<ns2:otherElem>
<ns3:thirdElem>
<ns3:thirdData>third</ns3:thirdData>
</ns3:thirdElem>
</ns2:otherElem>
</data>
</ns4:rootElem1>
</ns4:rootElem>
и все в порядке (за исключением data
, с которым не связано никакое пространство имен, я предполагаю, потому что это внутреннийtype).
Теперь это частично вопрос: вот
сгенерированный package-info.java
@javax.xml.bind.annotation.XmlSchema(namespace = "other", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package test.jaxb.generated;
Почему namespace
дано со ссылкой на other
?Мое корневое пространство имен - root
.(root.xsd
- это единственный файл, который мы передаем нашему Maven jaxb2-maven-plugin
; мы можем включить другие, это не имеет значения).
Неправильная замена package-info.java
Если мы перезаписываем сгенерированный файл следующим образом:
@javax.xml.bind.annotation.XmlSchema(
namespace = "root",
xmlns = {
@javax.xml.bind.annotation.XmlNs(prefix = "t", namespaceURI = "third"),
@javax.xml.bind.annotation.XmlNs(prefix = "o", namespaceURI = "other"),
@javax.xml.bind.annotation.XmlNs(prefix = "r", namespaceURI = "root")
},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package test.jaxb.generated;
, что мы изначально и сделали, потому что предполагали, что здесь нам нужно дать корневое пространство имен - это
Неверно сгенерированный XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<r:rootElem xmlns:t="third" xmlns:o="other" xmlns:r="root" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.example.com/schema.xsd">
<r:rootElem1>
<data>
<r:otherElem>
<t:thirdElem>
<t:thirdData>third</t:thirdData>
</t:thirdElem>
</r:otherElem>
</data>
</r:rootElem1>
</r:rootElem>
Теперь пространства имен красивые, но неправильные!otherElem
принадлежит o
, а не r
.
Изменение пространства имен в перезаписываемом файле обратно на other
исправляет ошибку, но снова:
вопрос в том, почемутребуемое пространство имен other
здесь?Не менее запутанным является тот факт, что импортированный слой third
является правильным в любом случае.
Проблема исправлена, но мы хотели бы понять концепцию.Чего нам не хватает?
РЕДАКТИРОВАТЬ:
Для полноты, вот раздел build
моего pom.xml
:
<build>
<plugins>
<plugin>
<!-- run xjc -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<executions>
<execution>
<id>xjc-generate_classes</id>
<goals>
<goal>xjc</goal>
</goals>
<configuration>
<packageName>test.jaxb.generated</packageName>
<schemaFiles>
root.xsd
</schemaFiles>
<schemaDirectory>${basedir}/src/main/resources/schemata</schemaDirectory>
<extension>true</extension>
<bindingDirectory>${basedir}/src/main/resources/bindings</bindingDirectory>
<outputDirectory>${basedir}/target/generated-sources/jaxb/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- overwrite created package-info.java -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<overwrite>true</overwrite>
<outputDirectory>${basedir}/target/generated-sources/jaxb/test/jaxb/generated</outputDirectory>
<resources>
<resource>
<directory>${basedir}/src/main/resources/bindings</directory>
<include>package-info.java</include>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>