Оставьте сущности как есть при анализе XML с помощью Woodstox

Я использую Woodstox для обработки XML, который содержит некоторые объекты (в первую очередь >) в значении одного из узлов. Чтобы использовать крайний пример, это примерно так:

<parent>&nbsp; &lt; &nbsp; &gt; &amp; &quot; &apos; &nbsp;</parent>

Я испробовал множество различных параметров конфигурации как для WstxInputFactory (IS_REPLACING_ENTITY_REFERENCES, P_TREAT_CHAR_REFS_AS_ENTS, P_CUSTOM_INTERNAL_ENTITIES...), так и для WstxOutputFactory, но независимо от того, что я пробовал, вывод всегда что-то вроде этого:

<parent>nbsp; &lt; nbsp; > &amp; " ' nbsp;</parent>

(&gt; преобразуется в >, &lt; остается прежним, &nbsp; теряет &...)

Я читаю XML с помощью XMLEventReader, созданного с помощью

XMLEventReader reader = wstxInputFactory.createXMLEventReader(new StringReader(fulltext));

после настройки WstxInputFactory.

Есть ли способ настроить Woodstox так, чтобы он просто игнорировал все объекты и выводил текст точно так же, как он был во входной строке?


person luthier    schedule 13.02.2019    source источник
comment
Удалось решить эту проблему? Я столкнулся с аналогичной проблемой, когда остается прежним, а преобразуется в ›   -  person Buzz    schedule 25.08.2020
comment
@Buzz В итоге я сделал что-то действительно хакерское, чем я не очень горжусь, но оно выполнило свою работу: перед обработкой XML я заменил все &gt;&apos; и &quot;) во входных данных XML на что-то вроде @@@HACKY_REPLACEMENT_FOR_GT@@@, а затем замените его обратно после завершения обработки. Это, вероятно, наименее элегантное/эффективное решение, но я просто не мог тратить на него больше времени. Надеюсь это поможет! :)   -  person luthier    schedule 27.08.2020


Ответы (2)


Прежде всего, вам нужно включить фактический код, поскольку «вывод всегда выглядит примерно так» не имеет смысла без объяснения того, как именно вы выводите анализируемый контент: вы можете печатать события, использовать какую-то библиотеку или, возможно, использовать поток Woodstox или автор событий.

Во-вторых: в XML есть разница между небольшим количеством предопределенных сущностей (lt, gt, apos, quot, amp) и произвольными определяемыми пользователем сущностями, такими как nbsp здесь. Первые можно использовать как есть, они уже определены; последние существуют только в том случае, если вы определяете их в DTD.

Обработка этих двух групп также отличается; прежний всегда будет расширяться, несмотря ни на что, и это по спецификации XML. Последнее будет разрешено (если разрешение не отключено), а затем расширено - или, если не определено, будет выдано исключение. Вы также можете указать собственный преобразователь, как указано в другом ответе; но это будет использоваться только для пользовательских сущностей (здесь &nbsp;).

В конце концов, также хорошо объяснять не столько то, что вы делаете, сколько то, чего вы пытаетесь достичь. Это поможет предложить вещи лучше, чем конкретные вопросы «как мне сделать X», которые могут не подойти.

А что касается конфигурации Woodstox, может быть, эта запись в блоге:

https://medium.com/@cowtowncoder/configuring-woodstox-xml-parser-woodstox-specific-properties-1ce5030a5173

поможет (а также 2 других из этой серии) — он охватывает существующие параметры конфигурации.

person StaxMan    schedule 14.02.2019
comment
Спасибо за ваш ответ! И извините, если мой вопрос был не так ясен, как должен был быть. Подводя итог: я пытаюсь добиться того, чтобы для ввода, содержащего, скажем, <parent>&gt;</parent>, после прохождения через WstxInputFactory и WstxOutputFactory вывод содержал точно такое же, <parent>&gt;</parent>, без расширения &gt;. Как вы думаете, это можно сделать? (еще раз спасибо!) - person luthier; 14.02.2019
comment
@LuTHieR Я не думаю, что это возможно именно так. Woodstox предлагает смещение символов для событий, так что может быть возможно выяснить что-то, что работает, но нет никакого способа предотвратить само разрешение. Обратите внимание, что во входных данных есть несколько других вещей, которые нельзя сохранить (например, пробелы вокруг атрибутов, нормализация перевода строки), символы (&, за которыми следует # и код символа, точка с запятой). - person StaxMan; 19.02.2019

Основные пять объектов XML (quot, amp, apos, lt, gt) будут обрабатываться всегда. Насколько я знаю, с Саксом невозможно получить их источник.

Для других сущностей вы можете обработать их вручную. Вы можете захватывать события до конца элемента и объединять значения:

    XMLInputFactory factory = WstxInputFactory.newInstance();
    factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, Boolean.FALSE);
    XMLEventReader xmlr = factory.createXMLEventReader(
            this.getClass().getResourceAsStream(xmlFileName));

    String value = "";
    while (xmlr.hasNext()) {
        XMLEvent event = xmlr.nextEvent();
        if (event.isCharacters()) {
            value += event.asCharacters().getData();
        }
        if (event.isEntityReference()) {
            value += "&" + ((EntityReference) event).getName() + ";";
        }
        if (event.isEndElement()) {
            // Assign it to the right variable
            System.out.println(value);
            value = "";
        }
    }

Для вашего примера ввода:

<parent>&nbsp; &lt; &nbsp; &gt; &amp; &quot; &apos; &nbsp;</parent>

Вывод будет:

&nbsp; < &nbsp; > & " ' &nbsp;

В противном случае, если вы хотите преобразовать все объекты, возможно, вы могли бы использовать собственный XmlResolver для необъявленных сущностей:

public class NaiveHtmlEntityResolver implements XMLResolver {

    private static final Map<String, String> ENTITIES = new HashMap<>();

    static {
        ENTITIES.put("nbsp", " ");
        ENTITIES.put("apos", "'");
        ENTITIES.put("quot", "\"");
        // and so on
    }

    @Override
    public Object resolveEntity(String publicID,
            String systemID,
            String baseURI,
            String namespace) throws XMLStreamException {
        if (publicID == null && systemID == null) {
            return ENTITIES.get(namespace);
        }
        return null;
    }
}

А затем скажите Woodstox использовать его для необъявленных сущностей:

    factory.setProperty(WstxInputProperties.P_UNDECLARED_ENTITY_RESOLVER, new NaiveHtmlEntityResolver());
person Iñaki Ibarrola Atxa    schedule 13.02.2019
comment
Спасибо, Инаки! Я пытаюсь сохранить gt&; как есть, а не расширять его, но, по крайней мере, это отличная отправная точка :) - person luthier; 14.02.2019