当前位置: 首页 > 面试题库 >

如何使用有时包含XML内容但有时不包含XML内容的JAXB编组字符串?

佟翰林
2023-03-14
问题内容

考虑这个例子-

我有一个称为Report的类,该类具有Message类型的字段。Message类具有一个称为“ body”的字段,该字段是一个字符串。“
body”可以是任何字符串, 但有时包含格式正确的XML内容 。如何确保当“正文”包含XML内容时,序列化采用XML结构的形式而不是当前的结构?

这是带有输出的代码-

报告 类别

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name = "Report")
@XmlType(propOrder = { "message"})
public class Report
{
    private Message message;
    public Message getMessage() { return message; }
    public void setMessage(Message m) { message = m; }
}

讯息 类别

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlType(propOrder = { "body" })
public class Message
{
    private String body;
    public String getBody() { return body; }
    @XmlElement
    public void setBody(String body) { this.body = body; }
}

主要

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;



public class SerializationTest
{
    public static void main(String args[]) throws Exception
    {
       JAXBContext jaxbContext = JAXBContext.newInstance(Report.class);
       Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
       jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

       Report report = new Report();
       Message message = new Message();

       message.setBody("Sample report message.");
       report.setMessage(message);
       jaxbMarshaller.marshal(report, System.out);

       message.setBody("<rootTag><body>All systems online.</body></rootTag>");
       report.setMessage(message);
       jaxbMarshaller.marshal(report, System.out);
    }
}

输出如下-

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Report>
    <message>
        <body>Sample report message.</body>
    </message>
</Report>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Report>
    <message>
        <body>&lt;rootTag&gt;&lt;body&gt;All systems online.&lt;/body&gt;&lt;/rootTag&gt;</body>
    </message>
</Report>

如您在上面的输出中看到的,对于“ body”的第二个实例,序列化产生了

 <body>&lt;rootTag&gt;&lt;body&gt;All systems online.&lt;/body&gt;&lt;/rootTag&gt;</body>

代替

<body><rootTag><body>All systems online.</body></rootTag></body>

如何解决这个问题呢?


问题答案:

注意: 我是 EclipseLink
JAXB(MOXy)的
负责人,并且是
JAXB(JSR-222)
专家组的成员。

使用@XmlAnyElement注解并指定来映射此用例DOMHandler。使用JAXB
RI执行此操作时似乎出现了错误,但是以下用例适用于EclipseLink JAXB(MOXy)。

BodyDomHandler

默认情况下,JAXB实现将未映射的内容表示为DOM节点。您可以利用DomHandler来表示DOM的替代表示,在这种情况下,我们将DOM表示为String

import java.io.*;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.DomHandler;
import javax.xml.transform.Source;
import javax.xml.transform.stream.*;

public class BodyDomHandler implements DomHandler<String, StreamResult> {

    private static final String BODY_START_TAG = "<body>";
    private static final String BODY_END_TAG = "</body>";

    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(BODY_START_TAG) + BODY_START_TAG.length();
        int endIndex = xml.indexOf(BODY_END_TAG);
        return xml.substring(beginIndex, endIndex);
    }

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

}

信息

下面是@XmlAnyElementMessage类上指定注释的方式。

import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlType;

@XmlType(propOrder = { "body" })
public class Message
{
    private String body;
    public String getBody() { return body; }
    @XmlAnyElement(BodyDomHandler.class)
    public void setBody(String body) { this.body = body; }
}

输出量

以下是运行your的输出SerialziationTest

<?xml version="1.0" encoding="UTF-8"?>
<Report>
   <message>
      <body>Sample report message.</body>
   </message>
</Report>
<?xml version="1.0" encoding="UTF-8"?>
<Report>
   <message>
      <body>
         <rootTag>
            <body>All systems online.</body>
         </rootTag>
      </body>
   </message>
</Report>

想要查询更多的信息

  • http://blog.bdoughan.com/2011/04/xmlanyelement-and-non-dom-properties.html
  • http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

注意-JAXB RI中的错误

JAXB参考实现中似乎存在一个错误,示例代码将导致如下所示的堆栈跟踪:

Exception in thread "main" javax.xml.bind.MarshalException
 - with linked exception:
[com.sun.istack.internal.SAXException2: unable to marshal type "java.lang.String" as an element because it is missing an @XmlRootElement annotation]
    at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:317)
    at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:243)
    at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:75)
    at forum12428727.SerializationTest.main(SerializationTest.java:20)
Caused by: com.sun.istack.internal.SAXException2: unable to marshal type "java.lang.String" as an element because it is missing an @XmlRootElement annotation
    at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:216)
    at com.sun.xml.internal.bind.v2.runtime.LeafBeanInfoImpl.serializeRoot(LeafBeanInfoImpl.java:126)
    at com.sun.xml.internal.bind.v2.runtime.property.SingleReferenceNodeProperty.serializeBody(SingleReferenceNodeProperty.java:100)
    at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:306)
    at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:664)
    at com.sun.xml.internal.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:141)
    at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:306)
    at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:561)
    at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:290)
    at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:462)
    at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:314)
    ... 3 more


 类似资料:
  • 我需要将 xml 文件转换为 Java 对象。 这是产品类别: 这是值类: 这里是Tunit类: 当我设置@XmlAttribute

  • 问题内容: 我希望您能够为我解决有关JAXB的问题提供帮助。 我有以下XML文件: XML可以在属性下包含其他元素(field1,field2),文本或两者。 和以下类: 我想将XML解组到上述类中。我遇到的问题是,在内容列表中,除了文本之外,还有其他字符,例如换行符和制表符。更具体地说,基于上述XML,当我尝试解组时会得到: 内容为[“ \ n \ t \ t”,“ \ n \ t \ t”,“

  • 我希望您能帮助我解决我面临的一个关于JAXB的问题。 我有以下XML文件: XML可以具有适当其他元素(字段1、字段2)、文本或两者。 和以下类: 我想将XML解组到上面的类中。我遇到的问题是,在内容列表中,除了文本之外,还有其他字符,如换行符和制表符。更具体地说,基于上面的XML,当我尝试解组时,我得到: 第一个内容为["\n\t\t","\n\t\t","\n\t"]的道具-它应该是一个空列表

  • 问题内容: 我想要不同的标签,您可以像在Android Market中一样在其中滑动。每个选项卡应使用一个片段,并使用一种方法。 这是我的FragmentPagerAdapter类: 对于每种片段类型/选项卡,我都有三个类: 每个片段都应该可自定义,这就是为什么我有三个类。 但是,该应用程序在getItem方法中崩溃。有任何想法吗?谢谢! 编辑:完整的MainActivity.java: 问题答案

  • 问题内容: 说,我有两节课: JAXB返回按照以下方式格式化的XML: 我的问题是 如何展平XML中的层次结构? 这样我有: 可以通过注释完成吗? 目前,我正在考虑为A创建一种包装类,该包装类将以我希望在XML中看到它们的方式构建字段。有没有更好的办法? 问题答案: 注意: 我是 EclipseLink JAXB(MOXy)的 负责人,并且是 JAXB 2(JSR-222) 专家组的成员。 您可以