【问题标题】:JAXB List Tag creating inner classJAXB List Tag 创建内部类
【发布时间】:2011-06-19 07:37:28
【问题描述】:

所以我们在表单中有一个 XSD 类型:

<xs:complexType name="Foo">
    <xs:all>
        <xs:element name="Bars">
            <xs:complexType>
                <xs:sequence>
                    <xs:element name="Bar" type="barType" maxOccurs="unbounded"/>
                </xs:sequence>
            </xs:complexType>
        </xs:element>
    </xs:all>
</xs:complexType>    

表示 XML:

<Foo>
    <!-- Elements snipped for brevity-->
    <Bars>
        <Bar>
            <!-- Bar Element -->
        </Bar>
    </Bars>
</Foo>

xjc 产生几乎正确的结果。唯一令人讨厌的是,“Bars”被创建为一个存储 Bars 列表的内部类。无论如何让 Bars 成为 Foo 中的一个列表,同时仍然保留上面的 XML?

【问题讨论】:

    标签: java jaxb xjc


    【解决方案1】:

    您可以执行以下操作:

    package example;
    
    import java.util.List;
    
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlElementWrapper;
    import javax.xml.bind.annotation.XmlRootElement;
    
    @XmlRootElement(name="Foo")
    public class Foo {
    
        private List<Bar> bar;
    
        public List<Bar> getBar() {
            return bar;
        }
    
        @XmlElementWrapper(name="Bars")
        @XmlElement(name="Bar")
        public void setBar(List<Bar> bar) {
            this.bar = bar;
        }
    
    }
    

    package example;
    
    public class Bar {
    
    }
    

    然后您可以使用以下代码处理您的 XML;

    package example;
    
    import java.io.File;
    
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.Marshaller;
    import javax.xml.bind.Unmarshaller;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Foo.class);
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            Foo foo = (Foo) unmarshaller.unmarshal(new File("src/forum128/input.xml"));
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(foo, System.out);
        }
    }
    

    【讨论】:

    • 不幸的是,我正试图从 xsd 转到 java 文件。
    • 我在my question here 中寻找类似的东西。 @XmlElementWrapper注解可以用XJC生成吗?我宁愿不手动修改生成的代码...
    • Blaise:首先,非常感谢您的所有帖子以及您的博客(例如 this post 也指此内容)。总是超级清晰,切中要害。我也在寻找一个简单的解决方案(即不涉及 xjc 插件),它可以让我们通过 xjc 生成@XmlElementWrapper。能够在 .xsd 中将元素声明为“void”或“pass-through”将是非常简洁的,即它的所有子元素将自动包含在父元素中(或者如果父元素也有那个标志)。
    • @PierreD - 我很高兴听到您发现这些信息很有用。生成@XmlElementWrapper 可能是最需要的功能之一,但截至目前确实需要 xjc-plugin。
    【解决方案2】:

    另一种方法是删除周围的 元素,XML 看起来不再那么漂亮了,但它会使 java 代码更易于阅读。与 xjc 的简单绑定(参见 http://jaxb.java.net/nonav/jaxb20-fcs/docs/vendorCustomizations.html)一起,它将生成非常漂亮和有用的 java 代码。

    【讨论】:

      【解决方案3】:

      也许下面的示例会有所帮助。

      XML 架构

       <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
          <xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      
            <xs:complexType name="test">
              <xs:sequence>
                <xs:element name="dataList" type="xs:string" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
                <xs:element name="str" type="xs:string" minOccurs="0"/>
              </xs:sequence>
            </xs:complexType>
          </xs:schema>
      

      Java 类:

      public class Test {
      
          protected List<String> dataList;
          protected String str;
          public List<String> getDataList() {
              if (dataList == null) {
                  dataList = new ArrayList<String>();
              }
              return this.dataList;
          }
      
          public String getStr() {
              return str;
          }
      
          public void setStr(String value) {
              this.str = value;
          }
      
      }
      

      编辑 1:

      您可以从 java 代码逆向工程到 xsd。 在 JAVA_HOME/bin 中有 schemagen 可执行文件。

      提供您的 java 代码,它会使用您的 java 类为您创建 XSD 架构。

      see this link

      schemagen myObj1.java myObj2.java
      

      【讨论】:

      • 这个 xsd 描述的 xml 像 (我认为)这并不完全我需要什么。
      【解决方案4】:

      当您将 Bars 定义为复杂类型时,Bars 将生成为单独的类。像这样我发现架构也更容易阅读。除非您将 maxOccurs 更改为大于 1 的值,否则 Bars 不会在 Foo 中列出 - 您不能在 xs:all 上执行此操作,但可以使用 xs:sequence。

      ...
          <xs:complexType name="Foo">
              <xs:all>
                  <xs:element name="Bars" type="Bars" />
              </xs:all>
          </xs:complexType>
      
          <xs:complexType name="Bars">
              <xs:sequence>
                  <xs:element name="Bar" type="barType" maxOccurs="unbounded" />
              </xs:sequence>
          </xs:complexType>
      ...
      

      运行 xjc 后: Foo.java:

          ...
          @XmlAccessorType(XmlAccessType.FIELD)
          @XmlType(name = "Foo", propOrder = {
      
          })
          public class Foo {
      
              @XmlElement(name = "Bars", required = true)
              protected Bars bars;
      
              public Bars getBars() {
                  return bars;
              }
      
              public void setBars(Bars value) {
                  this.bars = value;
              }
          }
      

      Bars.java:

          ...
          @XmlAccessorType(XmlAccessType.FIELD)
          @XmlType(name = "Bars", propOrder = {
              "bar"
          })
          public class Bars {
      
              @XmlElement(name = "Bar", required = true)
              protected List<String> bar;
      
              ...
          }
      

      使用 xs:seqence 获取 Bars 列表(maxOccurs="unbounded"): XSD:

          ...
          <xs:complexType name="Foo">
              <xs:sequence>
                  <xs:element name="Bars" type="Bars" maxOccurs="unbounded" />
              </xs:sequence>
          </xs:complexType>
      
          <xs:complexType name="Bars">
              <xs:sequence>
                  <xs:element name="Bar" type="barType" maxOccurs="unbounded" />
              </xs:sequence>
          </xs:complexType>
          ...
      

      Foo.java:

      ...
      @XmlAccessorType(XmlAccessType.FIELD)
      @XmlType(name = "Foo", propOrder = {
          "bars"
      })
      public class Foo {
      
          @XmlElement(name = "Bars", required = true)
          protected List<Bars> bars;
      
          public List<Bars> getBars() {
              if (bars == null) {
                  bars = new ArrayList<Bars>();
              }
              return this.bars;
          }
      }
      

      【讨论】:

        【解决方案5】:

        Bjarne Hansen 的 xjc 插件 (https://github.com/dmak/jaxb-xew-plugin) 将允许您使用 "Bars" 封闭元素,生成方便的 @XmlElementWrapper(name="Bars") 注释。

        【讨论】:

        • 正如其他一些关于此主题的帖子/cmets 中提到的,该插件似乎不适用于最近的 xjc。这两天我一直在纠结这个问题。我也喜欢从命令行使用 xjc,这个插件或多或少需要你编写一个 ant 目标,以及找到 jaxb.jar 在哪里等等。
        • @PierreD:如果插件在您需要的xjc 的某些版本上失败,请发帖到plugin bugtracker
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多