Sax parser: игнорирование специальных символов
Я использую Xerces для анализа моего xml-документа. Проблема в том, что в XML Escape-символы, как ' появится в символах() метод, как спасшийся. Мне нужно получить экранированные символы внутри метода characters () как есть.
спасибо.
UPD: пытался переопределить метод resolveEntity im потомок моего DefaultHandler. Из отладки видно, что он установлен как распознаватель сущностей для чтения xml, но код из переопределенного метода не вызывается.
4 ответов
Я думаю, что ваше решение не так уж плохо: несколько строк кода, чтобы делать то, что вы хотите.
Проблема в том, что startEntity
и endEntity
методы не предусмотрены ContentHandler
интерфейс, поэтому вы должны написать LexicalHandler
, который работает в сочетании с вашим ContentHandler
.
Обычно, использование XMLFilter
более элегантно, но вы должны работать с сущностью, поэтому вы все равно должны написать LexicalHandler
. Взгляните здесь для введения в использование фильтров SAX.
Я хотел бы чтобы показать вам способ, очень похожий на Ваш, который позволяет отделять операции фильтрации (wrapping & to &
например) из операций вывода (или что-то еще). Я написал свой собственный XMLFilter
на основе XMLFilterImpl
, который также реализует LexicalHandler
интерфейс. Этот фильтр содержит только код, связанный с entites escape / unescape.
public class XMLFilterEntityImpl extends XMLFilterImpl implements
LexicalHandler {
private String currentEntity = null;
public XMLFilterEntityImpl(XMLReader reader)
throws SAXNotRecognizedException, SAXNotSupportedException {
super(reader);
setProperty("http://xml.org/sax/properties/lexical-handler", this);
}
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (currentEntity == null) {
super.characters(ch, start, length);
return;
}
String entity = "&" + currentEntity + ";";
super.characters(entity.toCharArray(), 0, entity.length());
currentEntity = null;
}
@Override
public void startEntity(String name) throws SAXException {
currentEntity = name;
}
@Override
public void endEntity(String name) throws SAXException {
}
@Override
public void startDTD(String name, String publicId, String systemId)
throws SAXException {
}
@Override
public void endDTD() throws SAXException {
}
@Override
public void startCDATA() throws SAXException {
}
@Override
public void endCDATA() throws SAXException {
}
@Override
public void comment(char[] ch, int start, int length) throws SAXException {
}
}
и это мой главный, сDefaultHandler
as ContentHandler
который получает сущность в соответствии с фильтром код:
public static void main(String[] args) throws ParserConfigurationException,
SAXException, IOException {
DefaultHandler defaultHandler = new DefaultHandler() {
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
//This method receives the entity as is
System.out.println(new String(ch, start, length));
}
};
XMLFilter xmlFilter = new XMLFilterEntityImpl(XMLReaderFactory.createXMLReader());
xmlFilter.setContentHandler(defaultHandler);
String xml = "<html><head><title>title</title></head><body>&</body></html>";
xmlFilter.parse(new InputSource(new StringReader(xml)));
}
и это мой выход:
title
&
вероятно, вам это не нравится, в любом случае это альтернативное решение.
извините, но с SaxParser
я думаю, что у вас нет более элегантного способа.
вы также должны рассмотреть переключение на StaxParser
: это очень легко сделать, что вы хотите с XMLInputFactory.IS_REPLACING_ENTITY_REFERENCE
значение false. Если вам нравится это решение, вы должны взглянуть здесь.
Если вы предоставите LexicalHandler в качестве обратного вызова синтаксическому анализатору SAX, он сообщит вам о начале и конце каждой ссылки на объект, используя обратные вызовы startEntity() и endEntity ().
(обратите внимание, что javadoc на http://download.oracle.com/javase/1.5.0/docs/api/org/xml/sax/ext/LexicalHandler.html разговоры о "сущности" при правильной термин "сущности").
обратите внимание также, что нет способа получить парсер SAX, чтобы рассказать вам о числовом ссылки на символы, такие как ሴ
. Приложения должны относиться к ним точно так же, как к оригинальному персонажу, поэтому вы действительно не должны быть заинтересованы в них.
временное решение:
public void startEntity(String name) throws SAXException {
inEntity = true;
entityName = name;
}
public void characters(char[] ch, int start, int length) throws SAXException {
String data;
if (inEntity) {
inEntity = false;
data = "&" + entityName + ";";
} else {
data = new String(ch, start, length);
}
//TODO do something instead of System.out
System.out.println(data);
}
но все еще нужно элегантное решение.
есть еще один может: escapeXml
метод org.apache.commons.lang.StringEscapeUtils
класса.
попробуйте этот код в ваш characters(char[] ch, int start, int length)
способ:
String data=new String(ch, start, length);
String escapedData=org.apache.commons.lang.StringEscapeUtils.escapeXml(data);
вы можете скачать банку здесь.