【问题标题】:Unmarshaling XML CDATA strings as literals using JAXB使用 JAXB 将 XML CDATA 字符串解组为文字
【发布时间】:2015-03-25 14:52:32
【问题描述】:

考虑以下简单的XML 字符串:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<example>
    <value name="test">abcd</value>
</example>

以下代码定义了 2 个 Java 类(Example.classValue.class),可用于为字符串值 abcd 生成上述 XML 输出:

@XmlRootElement(name = "example")
public class Example {
  private Value value;
  private Example() {}
  public Value getValue() { return value; }

  public void setValue(Value value) { this.value = value; }

  @XmlAccessorType(XmlAccessType.FIELD)
  private static final class Value {
    @XmlValue
    private String value;
    @XmlAttribute(name="name")
    private String name;
    public Value() {}
    public String getValue() { return value; }


     public void setValue(String value) { this.value = value; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
      }
  }

要将上面的XML 字符串解组(反序列化)成原来的Example 对象,可以使用以下代码:

  public static void main(String[] args) throws Exception {
    JAXBContext context = JAXBContext.newInstance(Example.class);
    String input = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
      "<example>\n" +
      "    <value name=\"test\">abcd</value>\n" +
      "</example>";
    Unmarshaller um = context.createUnmarshaller();
    Example v = (Example)um.unmarshal(new ByteArrayInputStream(input.getBytes()));
    System.out.println(v.getValue().getValue());
  }

但是,如果上述main()方法中的字符串值从abcd更改为abcd&lt;&gt;或任何其他CDATA字符串,解组器会抛出异常:

org.xml.sax.SAXParseException; The content of elements must consist of well-formed character data or markup.

proposed solution 是使用带有XmlAnyElement 注释的自定义DOMHandler,但它似乎不起作用。

有没有办法将abcd&lt;&gt; 字符串反序列化为文字(即,不将其包含在CDATA 部分中)?

【问题讨论】:

  • 您链接到 (blog.bdoughan.com/2011/04/…) 的建议解决方案是将部分未编组的 XML 保留为 String。它仍然要求 XML 有效。

标签: java xml jaxb cdata


【解决方案1】:

唯一的方法是将特殊字符"&amp;'&lt;&gt;替换为字符引用&amp;qout;&amp;amp;

【讨论】:

    【解决方案2】:

    我认为您必须将 xml 字符串中的特殊字符替换为下面。

    abcd&lt;&gt; instead of `abcd<>`
    

    【讨论】:

    • 我们的想法是避免这样做。 :-)
    【解决方案3】:

    您是否尝试过创建一个在解组之前附加 CDATA 标记的方法?

     public String addCdataTags (String yourString){
            return "<![CDATA[" + yourString + "]]>"
         }
    

    这应该处理那些被错误地视为 xml 元素标签的 CDATA 字符串

    【讨论】:

    • 该方法应该添加到哪里?
    • 就在调用 unmarshaller.unmarshal(new ByteArrayInputStream(input.getBytes());
    • 这只是一个演示。问题是尝试解组未知输入,因此无法进行此类预处理。
    【解决方案4】:

    有没有办法将 abcd 字符串反序列化为文字 (即,不将其包含在 CDATA 部分中)?

    不,因为您的 XML 无效。

    问题是尝试解组未知输入,因此这样的 无法进行预处理

    您需要确保您的输入是有效的 XML 才能使用任何 XML 工具。

    无效的 XML

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <example>
        <value name="test">abcd<></value>
    </example>
    

    当您尝试解析上述 XML 时,您会遇到以下异常。异常来自 JAXB 使用的底层解析器。 XML 解析器依赖于表示元素标签的尖括号。将它们包含在元素内容中时必须特别小心。

    org.xml.sax.SAXParseException; The content of elements must consist of well-formed character data or markup.
    

    使用已解析的字符数据使其有效

    使 XML 有效的一种方法是将 &amp;lt; 替换为 &amp;lt; 并将 &amp;gt; 替换为 &amp;gt;。您的 JAXB 实现会将 XML 值 abcd&amp;lt;&amp;gt; 解组为 Stringabcd&amp;lt;&amp;gt;

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <example>
        <value name="test">abcd&lt;&gt;</value>
    </example>
    

    使用字符数据有效

    使 XML 有效的另一种方法是将字符内容包装在 CDATA 块中。 JAXB 会将&lt;![CDATA[abcd&lt;&gt;]]&gt; 解组为abcd&amp;lt;&amp;gt;。在编组时,它会将内容以abcd&amp;lt;&amp;gt; 的形式转换为 XML。

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <example>
        <value name="test"><![CDATA[abcd<>]]></value>
    </example>
    

    【讨论】:

    • 您在所有方面都是对的,CDATA 似乎是唯一的解决办法。
    猜你喜欢
    • 1970-01-01
    • 2016-02-05
    • 2018-01-06
    • 2014-11-21
    • 1970-01-01
    • 2021-07-29
    • 2014-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多