Попытка использовать XInclude с Java и разрешение фрагмента с помощью xml:id
Я пытался заставить XInclude работать в моем XML-документе и, наконец, заставить его работать в Oxygen XML, который я использую для создания XML-документов.
Затем я перешел к своему приложению, написанному на Java, но, похоже, оно не поддерживает какую-либо форму разрешения XPointer, кроме использования чего-то вроде: element(/1/2).
Очевидно, что это ужасная схема, которую нужно использовать, поскольку каждый раз, когда документ редактируется, XPointer должен меняться, чтобы отразить новую позицию узла в XML!
Схема, с которой я работал, просто использовала xml:id в целевом документе:
<foo>
<bar xml:id="ABCD" />
</foo>
а затем в другом документе:
<lorem>
<ipsum>
<xi:include href="target.xml" xpointer="ABCD" />
</ipsum>
</lorem>
Что я ожидаю (и получаю в кислороде) приводит к чему-то вроде:
<lorem>
<ipsum>
<bar xml:id="ABCD" />
</ipsum>
</lorem>.
Тем не менее, в Java это не с:
Ошибка чтения файла в формате XML (href='data/target.xml'). Причина: неудачное разрешение XPointer.
Если, однако, я изменяю тег включения, чтобы использовать
xpointer="element(/1/1)"
тогда это работает очень хорошо - но, как я уже сказал, это очень плохое решение.
Я просто использую реализации, которые включены в среду выполнения Java (1.8).
Вот код, который я использую:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setXIncludeAware(true);
Source resultSource = new
StreamSource(Gdx.files.internal("data/result.xsd").read());
Source targetSource = new
StreamSource(Gdx.files.internal("data/target.xsd").read());
Source[] schemaFiles = {targetSource, resultSource};
schema =
SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema")
.newSchema(schemaFiles);
factory.setSchema(schema);
builder = factory.newDocumentBuilder();
itemDoc = builder.parse(new
InputSource(Gdx.files.internal("data/result.xml").read()));
1 ответ
Согласно документации Apache Xerces по XInclude (который используется внутри для анализа XML в Java)
для кратких указателей и XPointers element() в настоящее время поддерживаются только идентификаторы DTD.
Это означает, что вы должны поместить объявления разметки, такие как следующие в ваш target.xml
файл (сообщающий анализатору XML, что id
атрибут должен рассматриваться как атрибут с ID
семантика и указание XInclude интерпретировать "голые" XPointers как ссылки на идентификаторы):
<!DOCTYPE foo [
<!ATTLIST bar id ID #IMPLIED>
]>
<foo>
<bar id="ABCD"/>
</foo>
Если вы сейчас используете следующий документ в качестве исходного XML (который вы назвали result.xml
в вашем примере кода, и который я отредактировал, чтобы содержать привязку URI пространства имен XInclude для xi
)
<lorem xmlns:xi="http://www.w3.org/2001/XInclude">
<ipsum>
<xi:include href="target.xml" xpointer="ABCD"/>
</ipsum>
</lorem>
тогда Xerces создаст Document
где обработка XInclude была выполнена по желанию (где я поместил данные вашего примера в target.xml
файл в том же каталоге, что и result.xml
файл):
<lorem xmlns:xi="http://www.w3.org/2001/XInclude">
<ipsum>
<bar id="ABCD" xml:base="target.xml"/>
</ipsum>
</lorem>
Код Java, который я использовал для создания документа, упрощен по сравнению с вашим примером и не содержит сторонних библиотек:
import java.io.*;
import javax.xml.*;
import javax.xml.parsers.*;
import javax.xml.validation.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.dom.*;
import org.w3c.dom.*;
public class t {
public static void main(String[] args) {
try {
DocumentBuilderFactory factory =
DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setXIncludeAware(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document itemDoc = builder.parse(new File("result.xml"));
System.out.println(serialize(itemDoc));
}
catch (Exception ex) {
ex.printStackTrace();
}
}
static String serialize(Document doc) throws Exception {
Transformer transformer =
TransformerFactory.newInstance().newTransformer();
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
return result.getWriter().toString();
}
}
Поскольку вы также используете проверку XML-схемы, я также хотел бы указать на потенциальное взаимодействие XInclude с XML-схемой, например. обсуждается в проверке схемы / пространства имен XInclude?, а также потенциальная альтернатива, обсуждаемая в Duplicate некоторых частях XML без переписывания их.