Как связать XMLReader, осведомленный о XInclude, с XMLFilter, чтобы включение XInclude выполнялось для любых элементов, которые изменил фильтр?
В Java синтаксический анализ XML - объединение выходных данных xi:include автор хотел использовать XInclude, но использовал неправильное пространство имен на include
элемент. Я подумал, что XMLFilter, поставленный перед синтаксическим анализатором XInclude, где XMLFilter заботится о корректировке пространства имен, может решить эту проблему (без необходимости редактировать файлы вручную, соответственно, без отдельного шага обработки, который сначала создает промежуточные файлы с исправленным пространством имен),
Поэтому я написал следующее XMLFilter
, расширяя XMLFilterImpl
что SAX обеспечивает:
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.XMLFilterImpl;
public class XIncludeNsFixup extends XMLFilterImpl {
static String correctURI = "http://www.w3.org/2001/XInclude";
static String oldURI = "http://www.w3.org/2003/XInclude";
@Override
public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
if (uri.equals(oldURI)) {
super.startElement(correctURI, localName, qName, atts);
}
else {
super.startElement(uri, localName, qName, atts);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (uri.equals(oldURI)) {
super.endElement(correctURI, localName, qName);
}
else {
super.endElement(uri, localName, qName);
}
}
@Override
public void startPrefixMapping(String prefix, String uri) throws SAXException {
if (uri.equals(oldURI)) {
super.startPrefixMapping(prefix, correctURI);
}
else {
super.startPrefixMapping(prefix, uri);
}
}
}
Затем я создал XInclude SAXParser соответственно XMLReader
быть прикованным к этому фильтру и загрузить образец документа в виде SAXSource
из этого фильтра в дефолт Transformer
построить DOMResult
:
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setXIncludeAware(true);
XMLReader inputReader = spf.newSAXParser().getXMLReader();
XMLFilter fixNs = new XIncludeNsFixup();
fixNs.setParent(inputReader);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer builder = tf.newTransformer();
DOMResult fixedInput = new DOMResult();
builder.transform(new SAXSource(fixNs, new InputSource("file3.xml")), fixedInput);
Document doc = (Document) fixedInput.getNode();
Transformer serializer = tf.newTransformer();
serializer.transform(new DOMSource(doc), new StreamResult(System.out));
Образец документа file3.xml
что я использовал есть один xi:xinclude
элемент в правильном пространстве имен XInclude и один в старом, не поддерживаемом пространстве имен:
<?xml version="1.0" encoding="UTF-8"?>
<contexts>
<context name="a">
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="reuse.xml"/>
<foo>Original text 1.</foo>
</context>
<context name="b">
<xi:include xmlns:xi="http://www.w3.org/2003/XInclude" href="reuse.xml"/>
<foo>Original text 2.</foo>
</context>
</contexts>
Я ожидаю, что фильтр сначала исправляет пространство имен, а затем XMLReader выполняет XInclude для обоих элементов. Однако при запуске кода с Java 1.8 вывод выглядит следующим образом:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><contexts>
<context name="a">
<text xml:base="reuse.xml">I am XIncluded text.</text>
<foo>Original text 1.</foo>
</context>
<context name="b">
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="reuse.xml"/>
<foo>Original text 2.</foo>
</context>
</contexts>
Таким образом, фильтр зафиксировал пространство имен на втором include
элемент, но XMLReader только применил включение XInclude на первом include
элемент.
Где я ошибся? Как связать фильтр и XMLReader с поддержкой XInclude, чтобы исправить пространство имен и выполнить включение XInclude в исправленные элементы пространства имен?
Для полноты вот reuse.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<text>I am XIncluded text.</text>
И полный код Java-программы для легкого тестирования:
import java.io.IOException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLFilter;
import org.xml.sax.XMLReader;
public class XIncludeTest1 {
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, TransformerConfigurationException, TransformerException {
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setNamespaceAware(true);
spf.setXIncludeAware(true);
XMLReader inputReader = spf.newSAXParser().getXMLReader();
XMLFilter fixNs = new XIncludeNsFixup();
fixNs.setParent(inputReader);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer builder = tf.newTransformer();
DOMResult fixedInput = new DOMResult();
builder.transform(new SAXSource(fixNs, new InputSource("file3.xml")), fixedInput);
Document doc = (Document) fixedInput.getNode();
Transformer serializer = tf.newTransformer();
serializer.transform(new DOMSource(doc), new StreamResult(System.out));
}
}
Я также попытался поместить последнюю версию Xerces Java от Apache в путь к классам, чтобы увидеть, устраняет ли она проблему, но вывод остается прежним.