Пропустить десериализацию элемента и получить весь контент в виде строки при разборе xml в java

У меня есть XML, как показано ниже:

<content>
  <p><b>Node:</b> Some information</p>
</content>

При десериализации этого XML я хочу получить содержимое внутри тега p в виде строки.

Например, если у меня есть класс Java, как показано ниже:

@Data
class Content {
  TextInParagraph p;
}

@Data
class TextInParagraph {
  String text;
}

У меня должно быть значение текста как "<b>Node:</b> Some information".

Есть ли способ сделать это выше, используя синтаксический анализатор XML JAXB или Jackson?

Я попытался десериализовать выше в Джексоне, но я получаю исключение ниже:

Expected END_ELEMENT, got event of type 1
java.io.IOException: Expected END_ELEMENT, got event of type 1

person parag mittal    schedule 22.01.2019    source источник
comment
См. документацию по JSON. Пробовали ли вы что-то вроде new ObjectMapper().readValue(json, Content.class);?   -  person Bsquare ℬℬ    schedule 22.01.2019
comment
Я пробовал что-то вроде выше, но получаю сообщение об ошибке: Ожидается END_ELEMENT, получено событие типа 1.   -  person parag mittal    schedule 22.01.2019
comment
Можете ли вы изменить этот XML и использовать CDATA для хранения кода HTML внутри узла content или p?   -  person Michał Ziober    schedule 22.01.2019
comment
Нет, я получаю это из другого сервиса, поэтому не могу редактировать.   -  person parag mittal    schedule 23.01.2019


Ответы (1)


К сожалению, это невозможно с jackson-dataformat-xml.

Однако с JAXB вы можете решить эту проблему, используя DomHandler

@XmlRootElement(name = "content")
@XmlAccessorType(XmlAccessType.FIELD)
public class Content {

    @XmlAnyElement(InnerXmlHandler.class)
    private String p;
}

Обработчик дома

import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.DomHandler;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.io.StringWriter;

public class InnerXmlHandler implements DomHandler<String, StreamResult> {

    private static final String START_TAG = "<p>";
    private static final String END_TAG = "</p>";

    private StringWriter xmlWriter = new StringWriter();

    public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) {
        return new StreamResult(xmlWriter);
    }

    public String getElement(StreamResult rt) {
        String xml = rt.getWriter().toString();
        int beginIndex = xml.indexOf(START_TAG) + START_TAG.length();
        int endIndex = xml.lastIndexOf(END_TAG);
        return xml.substring(beginIndex, endIndex);
    }

    public Source marshal(String n, ValidationEventHandler errorHandler) {
        try {
            String xml = START_TAG + n.trim() + END_TAG;
            StringReader xmlReader = new StringReader(xml);
            return new StreamSource(xmlReader);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

Это работает с образцом, который вы предоставили, но работает даже с вложенными тегами <p>, такими как:

<content>
  <p> This is some <ul><li>list</li></ul> and <p>nested paragraph</p></p>
</content>

Однако это работает только тогда, когда внутренний HTML/XML действителен. Следующее не будет работать и выдаст исключение, например The element type "ul" must be terminated by the matching end-tag "</ul>".

<content>
  <p> This is some <ul>invalid xml </p>
</content>

Это связано с внутренними компонентами JAXB, которые обходят все внутренние элементы, несмотря на наличие обработчика dom.

person thunderhook    schedule 30.01.2019