Как пропустить правильную форму для парсера Java DOM - PullRequest
2 голосов
/ 11 апреля 2011

Я знаю, что это задавали здесь несколько раз, но у меня другая проблема, связанная с этим.В моем случае приложение получает некорректную структуру dom, переданную в виде строки.Вот пример:

<div class='video yt'><div class='yt_url'>http://www.youtube.com/watch?v=U_QLu_Twd0g&feature=abcde_gdata</div></div>

Как видите, содержимое не является правильно сформированным.Теперь, если я попытаюсь выполнить синтаксический анализ с использованием обычного SAX или DOM-анализа, он выдаст исключение, которое понимают.с ';'delimiter.

В соответствии с требованием, мне нужно прочитать этот документ, добавить несколько дополнительных тегов div и отправить содержимое обратно в виде строки.Это прекрасно работает при использовании DOM-парсера, так как я могу прочитать структуру ввода и добавить дополнительные теги в нужном месте.

Я попытался использовать такие инструменты, как JTidy, чтобы выполнить предварительную обработку, а затем выполнить синтаксический анализ, но это приводит к преобразованию документа в полноценный html, который мне не нужен.Вот пример кода:


StringWriter writer = new StringWriter();
Tidy tidy = new Tidy(); // obtain a new Tidy instance
tidy.setXHTML(true);
tidy.parse(new ByteArrayInputStream(content.getBytes()), writer);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new ByteArrayInputStream(writer.toString().getBytes()));
// Traverse thru the content and add new tags
....
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);

Это полностью преобразует ввод в правильно сформированный HTML-документ.Затем становится трудно удалить HTML-теги вручную.Другой вариант, который я попробовал, состоял в том, чтобы использовать SAX2DOM, который также создает документ HTML.Вот пример кода.


ByteArrayInputStream is = new ByteArrayInputStream(content.getBytes());     
Parser p = new Parser();
p.setFeature(IContentExtractionConstant.SAX_NAMESPACE,true);
SAX2DOM sax2dom = new SAX2DOM();
p.setContentHandler(sax2dom);
p.parse(new InputSource(is));
Document doc = (Document)sax2dom.getDOM();

Буду признателен, если кто-нибудь поделится своими идеями.

Спасибо

1 Ответ

1 голос
/ 11 апреля 2011

Самый простой способ - заменить зарезервированные символы xml соответствующими объектами xml. Вы можете сделать это вручную:

content.replaceAll("&", "&amp;");

Если вы не хотите изменять строку перед ее анализом, я мог бы предложить вам другой способ, используя SaxParser, но это решение более сложное. В основном вы должны:

  1. написать LexicalHandler в комбинация с ContentHandler
  2. попросить парсер продолжить выполнение после фатальной ошибки ( ErrorHandler недостаточно)
  3. обрабатывать необъявленные сущности как простые Текст

UPDATE
Согласно вашему комментарию, я собираюсь добавить некоторые детали, касающиеся второго решения. Я написал класс, который расширяет DefaulHandler (реализация по умолчанию EntityResolver, DTDHandler, ContentHandler и ErrorHandler) и реализует LexicalHandler. Я расширил метод ErrorHandler fatalError (мои реализации ничего не делают вместо генерации исключения) и метод ContentHandler characters, который работает в сочетании с startEntity методом LexicalHandler.

public class MyHandler extends DefaultHandler implements LexicalHandler {

    private String currentEntity = null;

    @Override
    public void fatalError(SAXParseException e) throws SAXException {
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        String content = new String(ch, start, length);
        if (currentEntity != null) {
            content = "&" + currentEntity + content;
            currentEntity = null;
        }
        System.out.print(content);
    }

    @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 {
    }
}

Это моя основная задача, которая анализирует ваш xml неправильно сформированный. Очень важно setFeature, потому что без него парсер выдает SaxParseException несмотря на пустую реализацию ErrorHandler.

public static void main(String[] args) throws ParserConfigurationException,
        SAXException, IOException {
    String xml = "<div class='video yt'><div class='yt_url'>http://www.youtube.com/watch?v=U_QLu_Twd0g&feature=abcde_gdata</div></div>";
    SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
    XMLReader xmlReader = saxParser.getXMLReader();
    MyHandler myHandler = new MyHandler();
    xmlReader.setContentHandler(myHandler);
    xmlReader.setErrorHandler(myHandler);
    xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler",
            myHandler);
    xmlReader.setFeature(
            "http://apache.org/xml/features/continue-after-fatal-error",
            true);
    xmlReader.parse(new InputSource(new StringReader(xml)));
}

Эта главная распечатывает содержимое вашего элемента div, который содержит ошибку:

http://www.youtube.com/watch?v=U_QLu_Twd0g&feature=abcde_gdata

Имейте в виду, что это пример, который работает с вашим вводом, возможно, вам придется его завершить ... например, если у вас правильно экранированы некоторые символы, вы должны добавить несколько строк кода для обработки этой ситуации и т. Д.

Надеюсь, это поможет.

...