Вкратце: есть возможность с помощью директивы <xi:include href="..." /> в произвольное место XML вставлять содержимое из другого файла.
Штуковина вроде бы прикольная, но при работе с ней возникают некоторые трудности:
- XML редакторы не обрабатывают эту конструкцию должным образом.
- Java SAX парсеры без специальной настройки тоже не обрабатывают эту директиву.
Скорее всего происходит это потому, что XML вот такого вида в принципе не валидный:
<test:root> <xi:include href="..." /> </test:root>Для его правильной обработки необходимо произвести нечто вроде предпроцессинга, т.е. заменить <xi:include href="..." /> на содержимое соответствующего файла.
Итак, задача:
Есть XML и его надо загрузить. Ну скажем средствами DOM4J.
Отягощающие условия:
- Необходимо обязательно провалидировать загружаемый XML
- В атрибуте xsi:schemaLocation указаны не корректные данные. Настоящее место расположение файлов XSD необходимо задать программно
- Загружаемый элемент содержит директивы XInclude
Есть XSD и набор тестовых XML файлов (приведены в конце). Особенности XML:
- Некорректно указан xsi:schemaLocation (например "http://www.xml.test.org/test platform:/resource/dom4j_validation/src/test/resources/xsd/test.xsd" понимает только eclipse)
- 3 тестовых XML: невалидный, валидный и валидный с Xinclude директивами.
public abstract class BaseLoaderTest { protected abstract TestLoader getLoader(); @Test public void testInvalidXml() throws Exception { try { getLoader().tryToLoad("invalid.xml"); fail("Invalid XML was loaded without errors"); } catch (DocumentException e) { assertTrue(e.getMessage(), e.getMessage().contains("The content of element 'test:el1' is not complete")); } } @Test public void testValidXmlWithoutXInclude() throws Exception { Document result = getLoader().tryToLoad("valid.xml"); assertNotNull(result); } @Test public void testValidXmlWithXInclude() throws Exception { Document result = getLoader().tryToLoad("valid_with_xinclude.xml"); assertNotNull(result); } }
Начинаем со стандартного кода:
public Document tryToLoad(String xmlLocation) throws Exception { SAXReader reader = new SAXReader(true); reader.setProperty("http://java.sun.com/xml/jaxp/properties/schemaLanguage", "http://www.w3.org/2001/XMLSchema"); reader.setProperty("http://java.sun.com/xml/jaxp/properties/schemaSource", getSchemaFiles()); return reader.read(getResource(xmlLocation)); }В таком варианте мы включаем валидацию и указываем истинное месторасположение XSD файлов. Но testValidXmlWithXInclude() упорно валится :(
Потребовалось довольно много времени, для того, чтобы найти 2 заветные строчки кода, которые сделали счастье. Информация была найдена на сайте apache xerces. В итоге получилось нечто вот такое:
public Document tryToLoad(String xmlLocation) throws Exception { SAXReader reader = new SAXReader(true); reader.setProperty(JAXP_SCHEMA_LANGUAGE, XMLConstants.W3C_XML_SCHEMA_NS_URI); reader.setProperty(JAXP_SCHEMA_SOURCE, getSchemaFiles()); // enable XInclude directives processing reader.setFeature("http://apache.org/xml/features/xinclude", true); reader.setFeature("http://apache.org/xml/features/xinclude/fixup-base-uris", false); return reader.read(getResource(xmlLocation)); }
Содерживое тестовых XML /XSD файлов.
<?xml version="1.0" encoding="UTF-8"?> <schema xmlns="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.xml.test.org/test" xmlns:tns="http://www.xml.test.org/test" elementFormDefault="qualified"> <element name="root" type="tns:root-type" /> <complexType name="root-type"> <sequence> <element ref="tns:el1" minOccurs="1" maxOccurs="unbounded" /> </sequence> </complexType> <complexType name="level1-type"> <sequence> <element name="el2" type="tns:level2-type" minOccurs="1" maxOccurs="unbounded" nillable="false" /> </sequence> </complexType> <complexType name="level2-type"> <sequence> <element name="value" type="string" minOccurs="1" maxOccurs="unbounded" nillable="false" /> </sequence> </complexType> <element name="el1" type="tns:level1-type" nillable="false"/> </schema>
<?xml version="1.0" encoding="UTF-8"?> <test:root xmlns:test="http://www.xml.test.org/test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xml.test.org/test platform:/resource/dom4j_validation/src/test/resources/xsd/test.xsd"> <test:el1> <test:el2> <test:value>value1</test:value> </test:el2> </test:el1> <test:el1> <!— Missing a required element. --> </test:el1> </test:root>
<?xml version="1.0" encoding="UTF-8"?> <test:root xmlns:test="http://www.xml.test.org/test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xml.test.org/test platform:/resource/dom4j_validation/src/test/resources/xsd/test.xsd"> <test:el1> <test:el2> <test:value>value1</test:value> </test:el2> </test:el1> <test:el1> <test:el2> <test:value>value2_1</test:value> <test:value>value2_2</test:value> </test:el2> </test:el1> </test:root>
<?xml version="1.0" encoding="UTF-8"?> <test:root xmlns:test="http://www.xml.test.org/test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xi="http://www.w3.org/2001/XInclude" xsi:schemaLocation="http://www.xml.test.org/test platform:/resource/dom4j_validation/src/test/resources/xsd/test.xsd http://www.w3.org/2001/XInclude http://www.w3.org/2001/XInclude.xsd"> <xi:include href="valid_with_xinclude_part1.xml" parse="xml" /> <xi:include href="valid_with_xinclude_part2.xml" parse="xml" /> </test:root>
(ну и валидные valid_with_xinclude_part1.xml и valid_with_xinclude_part2.xml )
<?xml version="1.0" encoding="UTF-8"?> <test:el1 xmlns:test="http://www.xml.test.org/test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xml.test.org/test ./xsd/test.xsd"> <test:el2> <test:value>value1</test:value> </test:el2> </test:el1>
<?xml version="1.0" encoding="UTF-8"?> <test:el1 xmlns:test="http://www.xml.test.org/test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.xml.test.org/test ./xsd/test.xsd"> <test:el2> <test:value>value2_1</test:value> <test:value>value2_2</test:value> </test:el2> </test:el1>
Комментариев нет:
Отправить комментарий