Заменить & на & amp; используя Jackson ObjectMapper

В приложении, с которым я работаю, у нас есть требование преобразовать огромный JSON в еще больший XML. Структура обоих элементов очень различна, поэтому мы решили создать файл XML, соответствующий XSD, и заполнить поля с использованием языка унифицированных выражений. Например:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Objects xmlns="..">
  <Object>
    <Field>${json.field}</Field>
  <Object>
<Objects>

Замена ${json.field} делается с помощью JUEL

После запуска процесса JUEL мы демонтируем строку xml в объект и продолжаем процесс. Демонстрационный код выглядит примерно так:

  private XmlObjects unmarshal(StringReader xmlString) {
    try {
      Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
      return (XmlObjects) unmarshaller.unmarshal(xmlString);
    } catch (JAXBException e) {
      throw new RuntimeException(e);
    }
  }

Проблема, с которой мы сталкиваемся, заключается в том, что json.field может содержать символы, которые не разрешены в XML, например & или <,>.

Простое решение - заменить все & by & en описанным выше методом, но это не решит проблему <или>, и я не могу заменить это в этой точке.

То, что я хотел бы сделать, это использовать Джексона, чтобы сделать замену, когда json отображается в POJO, но я не могу найти способ сделать это. До сих пор я пытался создать кастом CharacterEscapes класс и установка, что к ObjectMapper но не сработало.

Итак, это тест, который суммирует все:

  @Test
  public void test() throws IOException {
    ObjectMapper objectMapper = Jackson.newObjectMapper();
    objectMapper.getFactory().setCharacterEscapes(new XMLCharacterEscapes());

    String json = "{\"variable\":\"a string with &\"}";
    FooJson fooJson = objectMapper.readValue(json, FooJson.class);
    assertEquals("a string with &amp;", fooJson.getVariable());
  }

Это XMLCharacterEscapes учебный класс:

public class XMLCharacterEscapes extends CharacterEscapes {

  private final int[] asciiEscapes;

  public XMLCharacterEscapes() {
    int[] esc = CharacterEscapes.standardAsciiEscapesForJSON();
    esc['&'] = CharacterEscapes.ESCAPE_CUSTOM;
    asciiEscapes = esc;
  }

  @Override
  public int[] getEscapeCodesForAscii() {
    return asciiEscapes;
  }

  @Override
  public SerializableString getEscapeSequence(int i) {
    return new SerializedString("&amp;");
  }
}

2 ответа

Поместите свое поле в раздел CDATA

<Field><![CDATA[${json.field}]]></Field>

Если я могу предложить альтернативу, можете ли вы вместо этого сделать так, чтобы ваш unmarshaller применил JUEL к значениям элемента при чтении XML? Или вы можете пройтись по графу объектов XML после демаршаллинга и применить JUEL к значениям элемента?

Изменить: Кажется, что проблема заключается только в порядке применения замен. Получив XML-документ, вы сможете установить любые значения, которые вам нравятся, и он позаботится о правильном экранировании.

Другие вопросы по тегам