【问题标题】:How do I wrap a section of xml in a CDATA tag using Jackson如何使用 Jackson 将一段 xml 包装在 CDATA 标记中
【发布时间】:2013-09-19 18:18:09
【问题描述】:

我有以下 java 对象

class MyXmlObject{
    @JsonProperty
    private InnerObject innerObject;
    @JsonProperty
    private String someOtherProperty;
}

当我使用

序列化它时
public String getXmlObjectAsXML(MyXmlObject myXmlObject){
    JacksonXmlModule module = new JacksonXmlModule();

    module.setDefaultUseWrapper(false);
    XmlMapper mapper = new XmlMapper(module);

    mapper.configure(SerializationFeature.INDENT_OUTPUT, true);

    String response = "";

    response = mapper.writeValueAsString(myXmlObject);
    return response;
}

我希望将 InnerObject 类包装在 CDATA 标记中。

处理这种情况的正确方法是什么?

【问题讨论】:

    标签: java xml-serialization jackson


    【解决方案1】:

    从 2.5 开始就有@JacksonXmlCDatahttps://github.com/FasterXML/jackson-dataformat-xml:

    @JacksonXmlCData 允许指定要在 CData 标记中序列化的属性值。

    【讨论】:

    • 哇,我不再需要这样做了,但知道真的很好
    【解决方案2】:

    我们有一个类似的用例。我们需要用 CDATA 包装的 XML 中的所有文本字段。这是我们需要实现的 API 的要求,我们在 API 中没有发言权。

    为了解决这个问题,我们创建了@StaxMan 建议的实现,以覆盖 XMLOutputFactory 和 XMLStreamWriter 以劫持 writeCharacters() 并改为调用 writeCData(),这似乎工作得很好。您可以在此处查看我们的确切代码(更改了包名称)的要点:

    https://gist.github.com/jbcpollak/8312151

    简而言之,我们创建了一个 CDataXmlOutputFactoryImpl 类,该类创建了一个 CDataXmlStreamWriter。不幸的是,我们需要包装目标类,而不是使用继承,因为它们都是最终的。此外,要使用的确切编写器是可变的,因此包装是一个更安全的选择。

    在工厂中,除了用纯传递函数包装所有其他方法外,您还需要为每个 createXMLStreamWriter() 函数提供类似的东西(有 4 个):

    public XMLStreamWriter createXMLStreamWriter(Writer w) 
        throws XMLStreamException
    {
    
        return new CDataXmlStreamWriter(f.createXMLStreamWriter(w));
    }
    

    其中f 是在类中构造的OutputFactoryImpl

    CDataXmlStreamWriter中,所有必要的函数都是w中方法的纯委托,除了下面的两个方法:

    public void writeCharacters(char[] text, int start, int len) 
        throws XMLStreamException
    {
        w.writeCharacters(text, start, len);
    }
    
    // All this code just to override this method
    public void writeCharacters(String text) throws XMLStreamException
    {
    
        w.writeCData(text);
    }
    

    这就是您需要做的所有事情。像这样使用你的新工厂:

    public void init() {
        XmlFactory factory = new XmlFactory(new InputFactoryImpl(),
                new CDataXmlOutputFactoryImpl());
        xmlMapper = new XmlMapper(factory);
        xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
    }
    

    完整的代码可以在上面的 Gist 中看到。

    如果您只需要 CDATA 中包含的几个字段,我不确定此解决方案是否可行。为此,我认为您需要修改 ToXmlGenerator,使其以某种方式了解您的模型(也许使用注释?),然后生成器将在必要时调用 writeCData()

    【讨论】:

    • 比我希望的要复杂得多,但比我对实际物理文本的破解要干净得多。
    • 同意,我希望 Jackson 代码更灵活一些。由于它们提供了覆盖工厂类的能力,我不明白为什么所有相​​关类都是最终的。如果 CData 原生支持注释,那就更好了。
    【解决方案3】:

    我不知道任何使输出使用 CDATA 部分的选项。

    但是为什么需要使用 CDATA 部分呢?在 XML CDATA 中,在语义上与常规文本部分没有区别。它只是为了方便手动编辑而存在。

    【讨论】:

    • 我们的 esb 需要它......我个人永远不会这样做。
    • 好的。不确定如何做到这一点——理论上你可以对XMLOutputFactory 进行子类化,以产生XMLStreamWriter 实例来劫持writeCharacters(),而不是调用writeCData。 Woodstox 有一些功能可以帮助委托呼叫,这可能会起作用。但我想不出默认功能;有相反的情况(“将所有文本输出为字符,即使指示使用 CDATA”)。
    • 哦——您也可以为 Jackson XML 模块提交功能请求。在那里实施它实际上很容易;调用writeCData() 而不是writeCharacters()。只要将它用于所有文本写入就可以了。
    【解决方案4】:

    我最终只是放入了一个占位符,对两个对象进行了编组,然后手动操作了字符串……不干净也不漂亮,但它起作用了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-08
      • 2016-02-05
      • 1970-01-01
      • 2014-03-09
      • 2015-04-30
      • 2019-08-13
      • 2016-09-24
      • 1970-01-01
      相关资源
      最近更新 更多