JAXB 如何将嵌套的 xml 元素解组为字符串?
How can JAXB unmarshal nested xml elements into a string?
我正在尝试将 xml 转换为我的 Java class
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Request")
public class Request {
@XmlElement(name="UserName")
private String username;
@XmlElement(name="Password")
private String password;
@XmlElement(name="XMLPost")
private String xmlPost;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getXmlPost() {
return xmlPost;
}
public void setXmlPost(String xmlPost) {
this.xmlPost = xmlPost;
}}
这是我的上下文
JAXBContext jc = JAXVContext.newInstance(Request.class, Report.class, Status.class);
StringReader reader = new StringReader(xml);
Unmarshaller unmarshaller = jc.createUnmarshaller();
下面是我如何一起使用它们
Request request = unmarshaller.unmarshal(reader);
在 Request
class 中,xmlPost
将包含 Report
的 xml 或 Status
的 xml 所以我想将它捕获到一个字符串中,以便我可以尝试解组每个案例。
Report
class 来自我无法控制的第 3 方请求。但是,当我尝试解组 Request
时,如果 XMLPost
字段中有任何 XML,它也会尝试解组它,即使我已经指定它应该只是一个 [=21] =].为什么我不能将 XMLPost
中的 xml 填充到 String
中?
感谢所有先进的帮助。
您可以使用自定义处理程序对其进行转换,请检查此post。我希望它能帮助您解决问题:http://blog.bdoughan.com/2011/04/xmlanyelement-and-non-dom-properties.html
你不能直接这样做,因为它不符合 XML 规范。
当你定义:
@XmlElement(name="XMLPost")
private String xmlPost;
这意味着根据 XML 规范的 JAXB 期望 XML 具有简单类型元素 XML 发布为 xs:string。不是另一个 XML 元素。
要在其中包含一个值,您的请求必须如下所示:
<Request>
<XMLPost>some string in it</XMLPost>
</Request>
因此,如果您想在其中包含另一个 XML 作为字符串,您必须以 XML 转义形式包含它,例如:
<Request>
<XMLPost><Report> ...xml escaped content... </Report></XMLPost>
</Request>
或作为 CDATA 元素。
<Request>
<XMLPost><![CDATA[<Report> ...xml content... </Report>]]></XMLPost>
</Request>
从其他人手中,您可以将两个字段作为复杂的 XML 元素
@XmlElement(name="Report")
private Report report;
@XmlElement(name="Status")
private Status status;
在那种情况下,您必须有 JAXB 类 用于报告和状态
那么如果你的请求有 Report 元素那么
报告字段将有它并且状态将为空
或者当请求有状态时,状态字段将有它并且报告字段将为空。
如果您需要 Report 和 Status 而无需使用 String 并单独解组它们,这可能是更合适的方法。这取决于您以及您需要如何处理这些元素...
就 XML 架构而言,您做了什么:
<xs:element name="Request">
<xs:complexType>
<xs:sequence>
<xs:element name="XMLPost" type="xs:string">
</xs:sequence>
</xs:complexType>
</xs:element>
对于第二种方法,它看起来像:
<xs:element name="Request">
<xs:complexType>
<xs:sequence>
<xs:element name="Report" minOccurs="0">
<xs:complexType>
<xs:sequence>
<!-- ... Report type definition ... -->
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Status" minOccurs="0">
<xs:complexType>
<xs:sequence>
<!-- ... Status type definition ... -->
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
最后,如果您只需要一个字段来保留 Report 或 Status 对象(不是 String),请将其定义为 Object
@XmlElement(name="XMLPost")
private Object xmlPost;
对应XSD:
<element name="XMLPost" type="xs:anyType" />
当然,当您处理您的请求时,您需要检查什么是 Class 的 xmlPost 对象
我真正要做的是创建一个 XMLPost
对象,其中包含可选的 report
和 status
字段。然后unmarshalling之后就可以看到populated了哪一个
但是要回答您原来的问题,您应该使用 XmlAdapter
(In JAXB, how to use @XmlJavaTypeAdapters annotation?)。以下是适配器的外观示例:
public class XmlPostStringAdapter extends XmlAdapter<XMLPost, String> {
@Override
public String unmarshal(XMLPost xmlPost) throws Exception {
StringWriter sw = new StringWriter();
JAXBContext jaxbContext = JAXBContext.newInstance(XmlPost.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.marshal(xmlPost, sw);
return sw.toString();
}
@Override
public XMLPost marshal(String xmlPost) throws Exception {
JAXBContext jaxbContext = JAXBContext.newInstance(XMLPost.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
return (XMLPost) jaxbUnmarshaller.unmarshal(new StringReader(xmlPost));
}
}
我正在尝试将 xml 转换为我的 Java class
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Request")
public class Request {
@XmlElement(name="UserName")
private String username;
@XmlElement(name="Password")
private String password;
@XmlElement(name="XMLPost")
private String xmlPost;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getXmlPost() {
return xmlPost;
}
public void setXmlPost(String xmlPost) {
this.xmlPost = xmlPost;
}}
这是我的上下文
JAXBContext jc = JAXVContext.newInstance(Request.class, Report.class, Status.class);
StringReader reader = new StringReader(xml);
Unmarshaller unmarshaller = jc.createUnmarshaller();
下面是我如何一起使用它们
Request request = unmarshaller.unmarshal(reader);
在 Request
class 中,xmlPost
将包含 Report
的 xml 或 Status
的 xml 所以我想将它捕获到一个字符串中,以便我可以尝试解组每个案例。
Report
class 来自我无法控制的第 3 方请求。但是,当我尝试解组 Request
时,如果 XMLPost
字段中有任何 XML,它也会尝试解组它,即使我已经指定它应该只是一个 [=21] =].为什么我不能将 XMLPost
中的 xml 填充到 String
中?
感谢所有先进的帮助。
您可以使用自定义处理程序对其进行转换,请检查此post。我希望它能帮助您解决问题:http://blog.bdoughan.com/2011/04/xmlanyelement-and-non-dom-properties.html
你不能直接这样做,因为它不符合 XML 规范。 当你定义:
@XmlElement(name="XMLPost")
private String xmlPost;
这意味着根据 XML 规范的 JAXB 期望 XML 具有简单类型元素 XML 发布为 xs:string。不是另一个 XML 元素。 要在其中包含一个值,您的请求必须如下所示:
<Request>
<XMLPost>some string in it</XMLPost>
</Request>
因此,如果您想在其中包含另一个 XML 作为字符串,您必须以 XML 转义形式包含它,例如:
<Request>
<XMLPost><Report> ...xml escaped content... </Report></XMLPost>
</Request>
或作为 CDATA 元素。
<Request>
<XMLPost><![CDATA[<Report> ...xml content... </Report>]]></XMLPost>
</Request>
从其他人手中,您可以将两个字段作为复杂的 XML 元素
@XmlElement(name="Report")
private Report report;
@XmlElement(name="Status")
private Status status;
在那种情况下,您必须有 JAXB 类 用于报告和状态 那么如果你的请求有 Report 元素那么 报告字段将有它并且状态将为空 或者当请求有状态时,状态字段将有它并且报告字段将为空。
如果您需要 Report 和 Status 而无需使用 String 并单独解组它们,这可能是更合适的方法。这取决于您以及您需要如何处理这些元素...
就 XML 架构而言,您做了什么:
<xs:element name="Request">
<xs:complexType>
<xs:sequence>
<xs:element name="XMLPost" type="xs:string">
</xs:sequence>
</xs:complexType>
</xs:element>
对于第二种方法,它看起来像:
<xs:element name="Request">
<xs:complexType>
<xs:sequence>
<xs:element name="Report" minOccurs="0">
<xs:complexType>
<xs:sequence>
<!-- ... Report type definition ... -->
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="Status" minOccurs="0">
<xs:complexType>
<xs:sequence>
<!-- ... Status type definition ... -->
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
最后,如果您只需要一个字段来保留 Report 或 Status 对象(不是 String),请将其定义为 Object
@XmlElement(name="XMLPost")
private Object xmlPost;
对应XSD:
<element name="XMLPost" type="xs:anyType" />
当然,当您处理您的请求时,您需要检查什么是 Class 的 xmlPost 对象
我真正要做的是创建一个 XMLPost
对象,其中包含可选的 report
和 status
字段。然后unmarshalling之后就可以看到populated了哪一个
但是要回答您原来的问题,您应该使用 XmlAdapter
(In JAXB, how to use @XmlJavaTypeAdapters annotation?)。以下是适配器的外观示例:
public class XmlPostStringAdapter extends XmlAdapter<XMLPost, String> {
@Override
public String unmarshal(XMLPost xmlPost) throws Exception {
StringWriter sw = new StringWriter();
JAXBContext jaxbContext = JAXBContext.newInstance(XmlPost.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.marshal(xmlPost, sw);
return sw.toString();
}
@Override
public XMLPost marshal(String xmlPost) throws Exception {
JAXBContext jaxbContext = JAXBContext.newInstance(XMLPost.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
return (XMLPost) jaxbUnmarshaller.unmarshal(new StringReader(xmlPost));
}
}