Вкратце: есть возможность с помощью директивы <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>
Комментариев нет:
Отправить комментарий