JAXB - Java/ XMLValue & XMLElement 冲突

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15495156/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 19:48:11  来源:igfitidea点击:

JAXB - Java/ XMLValue & XMLElement conflict

javajaxb

提问by Adam Sh

I have the next html, which I want to parse:

我有下一个 html,我想解析它:

My input: 
<div>
    <span id="x1x1"> bla bla </span>
</div>
<span>
    <div> bla bla </div>
</span>

My output in java:
    jaxbContext = JAXBContext.newInstance(Div.class);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
    jaxbUnmarshaller.unmarshal(file);
    System.out.println("id " + div1.getSpan().get(0).get(id) + "value " + div1.getSpan().get(0).get(id))
    // should print: id = x1x1 value = bla bla

I have the next class:

我有下一节课:

public class Span
    List<Div> div;

    public List<Div> getDiv() {
        return div;
    }

    @XmlElement
    public void setDiv(List<Div> div) {
        for (int i = 0 ; i<div.size(); i++){
            System.out.print("element")}
        this.div = div;
    }

and:

和:

public class Div 
    List<Span> span = div1.get

    @XmlElement
    public void setSpan(List<Span> span) {
        for (int i = 0 ; i<span.size(); i++){
            System.out.print("element")}
        this.span = span;
    }

    public List<Button> getSpan() {
        return span;
    }

Now, I want also the value of the span ("bla bla"). so I add to the class Span:

现在,我还想要跨度的值(“bla bla”)。所以我添加到课程中Span

String value;

public String getValue() {
    return value;
}

@XmlValue
public void setValue(String value) {
    this.value = value;
}

Bit it gives me the next error:

它给了我下一个错误:

 If a class has '@XmlElement' property, it cannot have '@XmlValue' property.

I try to use @XMLMixed, but without success. I would be happy for example with code example. Thanks.

我尝试使用@XMLMixed,但没有成功。例如,我会很高兴使用代码示例。谢谢。

回答by bdoughan

UPDATE

更新

Any element that can have both child notes that are text and elements is said to have mixed content. In JAXB this corresponds to the @XmlMixedannotation. @XmlMixedcan be used on its own on a collection property (see ORIGINAL ANSWER) or in combination with @XmlAnyElement, @XmlElementRef, or @XmlElementRefs. If the element can be anything you would use @XmlAnyElement, if it is one known element you would use @XmlElementRefand it is more than one known element you use @XmlElementRefs.

可以同时具有文本和元素的子注释的任何元素都被称为具有混合内容。在 JAXB 中,这对应于@XmlMixed注释。 @XmlMixed可以单独用于集合属性(请参阅原始答案)或与@XmlAnyElement@XmlElementRef、 或结合使用@XmlElementRefs。如果元素可以是您将使用的任何元素@XmlAnyElement,如果它是您将使用的一种已知元素,@XmlElementRef并且它是您使用的多个已知元素@XmlElementRefs

Span

跨度

If there will be both text and divelements within the same span element you could do the following by annotating a property with both @XmlElementRefand @XmlMixed. The element name specified on the @XmlElementRefannotation must correspond directly to the root element specified for the target class.

如果div在同一个 span 元素中同时包含文本和元素,您可以通过同时使用@XmlElementRef和注释属性来执行以下操作@XmlMixed@XmlElementRef注解上指定的元素名称必须直接对应于为目标类指定的根元素。

@XmlRootElement
public class Span {

    List<Object> items = new ArrayList<Object>();

    @XmlMixed
    @XmlElementRef(type=Div.class, name="div")
    public List<Object> getItems() {
        return items;
    }

    public void setItems(List<Object> mixed) {
        this.items = items;
    }


}

Div

分区

The metadata for Divis almost identical to the metadata specified for Span.

的元数据Div几乎与为 指定的元数据相同Span

@XmlRootElement
public class Div {

    List<Object> items = new ArrayList<Object>();

    @XmlElementRef(name="span", type=Span.class)
    @XmlMixed
    public List<Object> getItems() {
        return items;
    }

    public void setItems(List<Object> items) {
        this.items = items;
    }

}

Demo

演示

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Span.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Span span = (Span) unmarshaller.unmarshal(new StringReader("<span>Text<div>Text2</div>Text3</span>"));
        System.out.println(span.getItems());

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(span, System.out);
    }

}

Output

输出

[Text, forum15495156.Div@289f6ae, Text3]
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<span>Text<div>Text2</div>Text3</span>


ORIGINAL ANSWER

原答案

You could add a List<String>property annotated with @XmlMixedto your Spanclass:

你可以在你的类中添加一个List<String>注释的属性:@XmlMixedSpan

Span

跨度

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Span {
    List<Div> div;
    List<String> mixed;

    @XmlMixed
    public List<String> getMixed() {
        return mixed;
    }

    public void setMixed(List<String> mixed) {
        this.mixed = mixed;
    }

    public List<Div> getDiv() {
        return div;
    }

    @XmlElement
    public void setDiv(List<Div> div) {
        for (int i = 0; i < div.size(); i++) {
            System.out.print("element");
        }
        this.div = div;
    }
}

Demo

演示

import java.io.StringReader;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Span.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Span span1 = (Span) unmarshaller.unmarshal(new StringReader("<span>bla bla bla</span>"));
        System.out.println(span1.getMixed());

        Span span2 = (Span) unmarshaller.unmarshal(new StringReader("<span><div/><div/></span>"));
        System.out.println(span2.getDiv());
    }

}

Output

输出

[bla bla bla]
elementelement[forum15495156.Div@1f80ce47, forum15495156.Div@4166a779]

回答by Christian Trimble

Creating Annotated JAXB Classes from Example XML Documents

从示例 XML 文档创建带注释的 JAXB 类

Often, XML documents that you need to bind with JAXB do not come with an XSD for the content, but there are some great tools for automating this work, if you have an XSD. This is the process I use to fill this gap quickly and get quality binding code. Hopefully this helps answer this question and provides a general solution for this type of problem.

通常,需要与 JAXB 绑定的 XML 文档不附带内容的 XSD,但是如果您有 XSD,则有一些很棒的工具可以自动执行此工作。这是我用来快速填补这一空白并获得高质量绑定代码的过程。希望这有助于回答这个问题并为此类问题提供通用解决方案。

High Level Process

高级流程

This is the process that I used to create the code for this random piece of XML:

这是我用来为这个随机的 XML 片段创建代码的过程:

  1. Get a good quality example.
  2. Create an XSD from the example, using a tool called Trang.
  3. Generate your binding code from the XSD.
  1. 得到一个高质量的例子。
  2. 使用名为Trang的工具从示例创建 XSD 。
  3. 从 XSD 生成绑定代码。

The entire process took me under 5 minutes, with the tools preinstalled, and produces high quality results. This is a very simple example, but the complexity of the example XML document could easily go up, without increasing the process time or lowering quality.

整个过程用了不到 5 分钟,预装了工具,并产生了高质量的结果。这是一个非常简单的示例,但是示例 XML 文档的复杂性很容易增加,而不会增加处理时间或降低质量。

Creating a Good Quality Example

创建一个高质量的例子

The example document is the most important part of this process. For more complex structures, you may need several documents to capture the information that you need, but we will stick to a single document case. We can make an example for the problem by wrapping the provided input in a <div/>, to create a file called example.xml:

示例文档是此过程中最重要的部分。对于更复杂的结构,您可能需要多个文档来获取所需的信息,但我们将坚持使用单个文档案例。我们可以通过将提供的输入包装在 a<div/>中来创建一个名为 的文件,从而为该问题制作一个示例example.xml

<div>
  <div>
    <span id="x1x1"> bla bla </span>
  </div>
  <span>
    <div> bla bla </div>
  </span>
</div>

This example demonstrates that the <div/>s and <span/>s can be nested in each other and contain content.

此示例演示<div/>s 和<span/>s 可以相互嵌套并包含内容。

NOTE: This HTML fragment is not valid, since block level elements cannot be nested inside inline elements. An "off the shelf" schema, and code generated from it, would probably choke on this input.

注意:此 HTML 片段无效,因为块级元素不能嵌套在内联元素中。“现成的”模式以及从中生成的代码可能会阻塞在此输入上。

Create an XSD From the Example

从示例创建 XSD

This is the voodoo step in this process. Creating the XSD by hand would introduce a lot of work and possibility for error. Without an automated process, you might as well ditch the complexity of the generator and hand code the annotations. Luckily, there is a tool called Trangthat will fill this gap.

这是这个过程中的伏都教步骤。手动创建 XSD 会引入大量工作和出错的可能性。如果没有自动化流程,您不妨放弃生成器的复杂性并手动编写注释。幸运的是,有一个名为Trang的工具可以填补这一空白。

Trangcan do a lot of things, but one task that it excels at is producing XSDs from XML documents. For simple structures, it can completely handle this step. For more complex input, it can get you most of the way there.

Trang可以做很多事情,但它擅长的一项任务是从 XML 文档生成 XSD。对于简单的结构,它完全可以处理这一步。对于更复杂的输入,它可以帮助您完成大部分工作。

Trang is available from Maven Centralat this vector:

Trang 可从Maven Central在此向量处获得:

<dependency>
  <groupId>com.thaiopensource</groupId>
  <artifactId>trang</artifactId>
  <version>20091111</version>
</dependency>

You can download and transform the example.xmldocument with these commands:

您可以example.xml使用以下命令下载和转换文档:

wget http://repo1.maven.org/maven2/com/thaiopensource/trang/20091111/trang-20091111.jar
java -jar trang-20091111.jar example.xml example.xsd

This produces example.xsd:

这产生example.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xs:element name="div">
    <xs:complexType mixed="true">
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element ref="div"/>
        <xs:element ref="span"/>
      </xs:choice>
    </xs:complexType>
  </xs:element>
  <xs:element name="span">
    <xs:complexType mixed="true">
      <xs:sequence>
        <xs:element minOccurs="0" maxOccurs="unbounded" ref="div"/>
      </xs:sequence>
      <xs:attribute name="id" type="xs:NCName"/>
    </xs:complexType>
  </xs:element>
</xs:schema>

For simple documents, that is usually all it takes. For more complex structures, you may have to edit this file a little, but at least you have a working XSD as a starting point.

对于简单的文档,这通常就是全部。对于更复杂的结构,您可能需要稍微编辑此文件,但至少您有一个可用的 XSD 作为起点。

Generate Your Binding Code From the XSD

从 XSD 生成绑定代码

Now that we have an XSD, we can leverage the XJCtool and produce the binding code that we are looking for. To run XJC, pass it an XSD, the package you want to create, and a src directory. These two commands will generate the code for example.xsdin a package called example:

现在我们有了一个 XSD,我们可以利用XJC工具并生成我们正在寻找的绑定代码。要运行 XJC,请将 XSD、要创建的包和 src 目录传递给它。这两个命令将example.xsd在名为 的包中生成代码example

mkdir src
xjc -d src -p example example.xsd

Now, you will have the following files in the srcdirectory:

现在,您将在src目录中拥有以下文件:

src/example/Div.java
src/example/ObjectFactory.java
src/example/Span.java

I have included the contents of the files at the end of this article, but here is the piece we are interested in, from Span.java:

我在本文末尾包含了文件的内容,但这是我们感兴趣的部分,来自Span.java

@XmlElementRefs({
    @XmlElementRef(name = "div", type = Div.class),
    @XmlElementRef(name = "span", type = Span.class)
})
@XmlMixed
protected List<Object> content;

Although hand coding the annotations can work, automating the creation of these files can save time and improve quality. It also gives you access to all of the plugins that are available for the XJC tool.

尽管手动编码注释可以工作,但自动创建这些文件可以节省时间并提高质量。它还使您可以访问 XJC 工具可用的所有插件。



Complete Files Generated by XJC

XJC生成的完整文件

example/Div.java:

示例/ Div.java:

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2013.03.22 at 01:15:22 PM MST 
//


package example;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlElementRefs;
import javax.xml.bind.annotation.XmlMixed;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;choice maxOccurs="unbounded" minOccurs="0">
 *         &lt;element ref="{}div"/>
 *         &lt;element ref="{}span"/>
 *       &lt;/choice>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "content"
})
@XmlRootElement(name = "div")
public class Div {

    @XmlElementRefs({
        @XmlElementRef(name = "div", type = Div.class),
        @XmlElementRef(name = "span", type = Span.class)
    })
    @XmlMixed
    protected List<Object> content;

    /**
     * Gets the value of the content property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the content property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getContent().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link Div }
     * {@link String }
     * {@link Span }
     * 
     * 
     */
    public List<Object> getContent() {
        if (content == null) {
            content = new ArrayList<Object>();
        }
        return this.content;
    }

}

example/Span.java

示例/Span.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2013.03.22 at 01:15:22 PM MST 
//


package example;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlMixed;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;


/**
 * <p>Java class for anonymous complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType>
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;element ref="{}div" maxOccurs="unbounded" minOccurs="0"/>
 *       &lt;/sequence>
 *       &lt;attribute name="id" type="{http://www.w3.org/2001/XMLSchema}NCName" />
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "content"
})
@XmlRootElement(name = "span")
public class Span {

    @XmlElementRef(name = "div", type = Div.class)
    @XmlMixed
    protected List<Object> content;
    @XmlAttribute
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    @XmlSchemaType(name = "NCName")
    protected String id;

    /**
     * Gets the value of the content property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the content property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getContent().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link Div }
     * {@link String }
     * 
     * 
     */
    public List<Object> getContent() {
        if (content == null) {
            content = new ArrayList<Object>();
        }
        return this.content;
    }

    /**
     * Gets the value of the id property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getId() {
        return id;
    }

    /**
     * Sets the value of the id property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setId(String value) {
        this.id = value;
    }

}

example/ObjectFactory.java

示例/ObjectFactory.java

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 in JDK 6 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2013.03.22 at 01:15:22 PM MST 
//


package example;

import javax.xml.bind.annotation.XmlRegistry;


/**
 * This object contains factory methods for each 
 * Java content interface and Java element interface 
 * generated in the example package. 
 * <p>An ObjectFactory allows you to programatically 
 * construct new instances of the Java representation 
 * for XML content. The Java representation of XML 
 * content can consist of schema derived interfaces 
 * and classes representing the binding of schema 
 * type definitions, element declarations and model 
 * groups.  Factory methods for each of these are 
 * provided in this class.
 * 
 */
@XmlRegistry
public class ObjectFactory {


    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: example
     * 
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link Div }
     * 
     */
    public Div createDiv() {
        return new Div();
    }

    /**
     * Create an instance of {@link Span }
     * 
     */
    public Span createSpan() {
        return new Span();
    }

}