У меня есть установка JAXB, где я использую @XmlJavaTypeAdapter для замены объектов типа Person
с объектами типа PersonRef
то единственное содержит UUID человека. Это работает превосходное. Однако сгенерированная XML повторно объявляет то же пространство имен (xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
) каждый раз это используется. В то время как это обычно хорошо, это просто не чувствует себя хорошо.
Как я могу настроить JAXB для объявления xmlns:xsi в самом начале документа? Я могу вручную добавить объявления пространства имен к корневому элементу?
Вот пример того, что я хочу к achive:
Текущий:
<person uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a">
<relation type="CHILD">
<to xsi:type="personRef" uuid="56a930c0-5499-467f-8263-c2a9f9ecc5a0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</relation>
<relation type="CHILD">
<to xsi:type="personRef" uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
</relation>
<!-- SNIP: some more relations -->
</person>
Требуемый:
<person uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<relation type="CHILD">
<to xsi:type="personRef" uuid="56a930c0-5499-467f-8263-c2a9f9ecc5a0"/>
</relation>
<relation type="CHILD">
<to xsi:type="personRef" uuid="6ec0cf24-e880-431b-ada0-a5835e2a565a"/>
</relation>
<!-- SNIP: some more relations -->
</person>
Вы можете сделать это с помощью кода:
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapper() {
@Override
public String[] getPreDeclaredNamespaceUris() {
return new String[] {
XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI
};
}
@Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
if (namespaceUri.equals(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI))
return "xsi";
if (namespaceUri.equals(XMLConstants.W3C_XML_SCHEMA_NS_URI))
return "xs";
if (namespaceUri.equals(WellKnownNamespace.XML_MIME_URI))
return "xmime";
return suggestion;
}
});
Похоже на проблему настройки пространства имен настройки JAXB
Когда вы маршалируете XML-документ с помощью JAXB 1.0, объекта Marshaller, объекта JAXB, который управляет процессом маршалинг, предоставляет объявления пространств имен в результирующем XML-документе. Иногда Marshaller создает множество объявлений пространств имен, которые выглядят избыточными, например:
<?xml version="1.0"?>
<root>
<ns1:element xmlns:ns1="urn:foo"> ... </ns1:element>
<ns2:element xmlns:ns2="urn:foo"> ... </ns2:element>
<ns3:element xmlns:ns3="urn:foo"> ... </ns3:element>
</root>
JAXB 2.0 изменяет это поведение. Если вы используете JAXB 2.0 (или более позднюю версию) для маршалинга XML-документа, Marshaller объявляет все статически известные универсальные идентификаторы ресурсов (URI) пространства имен, то есть те URI, которые используются в качестве имен элементов или атрибутов в аннотациях JAXB.
JAXB может также объявлять дополнительные пространства имен в середине документа XML, например, когда полное имя (
QName
), которое используется в качестве значения атрибута или элемента, требует нового URI пространства имен, или когда Узлу объектной модели документа (DOM) в дереве содержимого требуется новый URI пространства имен. Такое поведение может привести к созданию XML-документа, в котором будет много объявлений пространств имен с автоматически сгенерированными префиксами пространств имен.Проблема в том, что автоматически сгенерированные префиксы пространства имен, такие как ns1, ns2 и ns3, не удобны для пользователя - они обычно не помогают людям понять упорядоченный XML.
К счастью, JAXB 2.0 (или более поздняя версия) предоставляет интерфейс поставщика услуг (SPI) с именем
com.sun.xml.bind.marshaller.NamespacePrefixMapper
, который можно использовать для указания более полезных префиксов пространства имен для сортировки.Когда программа JAXBSample упорядочивает XML-документ в первый раз, она делает это без использования класса
NamespacePrefixMapper
. В результате Marshaller автоматически генерирует префикс пространства имен, в данном случае ns2.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:JustAnElement xmlns:ns2="a">
<foo>true</foo>
</ns2:JustAnElement>
Пример конфигурации, исключающей повторение пространства имен:
Второй маршаллинг, выполняемый программой
JAXBSample
, использует классNamespacePrefixMapper
следующим образом:
NamespacePrefixMapper m = new PreferredMapper();
marshal(jc, e, m);
public static class PreferredMapper extends NamespacePrefixMapper {
@Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
return "mappedNamespace" + namespaceUri;
}
}
getPreferredPrefix ()
в классеPreferredMapper
возвращает предпочтительный префикс, в данном случае,mappedNamespacea
, который должен быть объявлен в корневом элементе упорядоченного XML.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<mappedNamespacea:JustAnElement xmlns:mappedNamespacea="a">
<foo>true</foo>
</mappedNamespacea:JustAnElement>
Это XML, поэтому вы можете обработать вывод с помощью DOM или XSLT, чтобы избавиться от многочисленных ссылок на пространство имен.
Не , что красиво, но вы можете добавить пустую schemaLocation к корневому элементу:
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "");