2017-01-14 80 views
3

我需要將archetype-catalog.xml文件的內容解析爲Java對象結構。爲此,我想我會用好舊的JAXB。於是,我找了XML文件的xsd定義和生成的JAXB類出來的:使用JAXB解組xml文件

ArchetypeCatalog.java

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.XmlType; 


/** 
* 0.0.0+ 
* 
* <p>Java class for ArchetypeCatalog complex type. 
* 
* <p>The following schema fragment specifies the expected content contained within this class. 
* 
* <pre> 
* &lt;complexType name="ArchetypeCatalog"> 
* &lt;complexContent> 
*  &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> 
*  &lt;all> 
*   &lt;element name="archetypes" minOccurs="0"> 
*   &lt;complexType> 
*    &lt;complexContent> 
*    &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> 
*     &lt;sequence> 
*     &lt;element name="archetype" type="{http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0}Archetype" maxOccurs="unbounded" minOccurs="0"/> 
*     &lt;/sequence> 
*    &lt;/restriction> 
*    &lt;/complexContent> 
*   &lt;/complexType> 
*   &lt;/element> 
*  &lt;/all> 
*  &lt;/restriction> 
* &lt;/complexContent> 
* &lt;/complexType> 
* </pre> 
* 
* 
*/ 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "ArchetypeCatalog", propOrder = { 

}) 
public class ArchetypeCatalog { 

    protected ArchetypeCatalog.Archetypes archetypes; 

    /** 
    * Gets the value of the archetypes property. 
    * 
    * @return 
    *  possible object is 
    *  {@link ArchetypeCatalog.Archetypes } 
    *  
    */ 
    public ArchetypeCatalog.Archetypes getArchetypes() { 
     return archetypes; 
    } 

    /** 
    * Sets the value of the archetypes property. 
    * 
    * @param value 
    *  allowed object is 
    *  {@link ArchetypeCatalog.Archetypes } 
    *  
    */ 
    public void setArchetypes(ArchetypeCatalog.Archetypes value) { 
     this.archetypes = value; 
    } 


    /** 
    * <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 name="archetype" type="{http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0}Archetype" maxOccurs="unbounded" minOccurs="0"/> 
    *  &lt;/sequence> 
    *  &lt;/restriction> 
    * &lt;/complexContent> 
    * &lt;/complexType> 
    * </pre> 
    * 
    * 
    */ 
    @XmlAccessorType(XmlAccessType.FIELD) 
    @XmlType(name = "", propOrder = { 
     "archetype" 
    }) 
    public static class Archetypes { 

     protected List<Archetype> archetype; 

     /** 
     * Gets the value of the archetype 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 archetype property. 
     * 
     * <p> 
     * For example, to add a new item, do as follows: 
     * <pre> 
     * getArchetype().add(newItem); 
     * </pre> 
     * 
     * 
     * <p> 
     * Objects of the following type(s) are allowed in the list 
     * {@link Archetype } 
     * 
     * 
     */ 
     public List<Archetype> getArchetype() { 
      if (archetype == null) { 
       archetype = new ArrayList<Archetype>(); 
      } 
      return this.archetype; 
     } 

    } 

} 

Archetype.java

import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlType; 


/** 
* 
*    Informations to point to an Archetype referenced in the catalog. 
*   
* 
* <p>Java class for Archetype complex type. 
* 
* <p>The following schema fragment specifies the expected content contained within this class. 
* 
* <pre> 
* &lt;complexType name="Archetype"> 
* &lt;complexContent> 
*  &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"> 
*  &lt;all> 
*   &lt;element name="groupId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> 
*   &lt;element name="artifactId" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> 
*   &lt;element name="version" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> 
*   &lt;element name="repository" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> 
*   &lt;element name="description" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/> 
*  &lt;/all> 
*  &lt;/restriction> 
* &lt;/complexContent> 
* &lt;/complexType> 
* </pre> 
* 
* 
*/ 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "Archetype", propOrder = { 

}) 
public class Archetype { 

    protected String groupId; 
    protected String artifactId; 
    protected String version; 
    protected String repository; 
    protected String description; 

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

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

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

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

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

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

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

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

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

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

} 

ObjectFactory.java

import javax.xml.bind.JAXBElement; 
import javax.xml.bind.annotation.XmlElementDecl; 
import javax.xml.bind.annotation.XmlRegistry; 
import javax.xml.namespace.QName; 


@XmlRegistry 
public class ObjectFactory { 

    private final static QName _ArchetypeCatalog_QNAME = new QName("http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0", "archetype-catalog"); 


    public ObjectFactory() { 
    } 

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

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

    /** 
    * Create an instance of {@link ArchetypeCatalog.Archetypes } 
    * 
    */ 
    public ArchetypeCatalog.Archetypes createArchetypeCatalogArchetypes() { 
     return new ArchetypeCatalog.Archetypes(); 
    } 

    /** 
    * Create an instance of {@link JAXBElement }{@code <}{@link ArchetypeCatalog }{@code >}} 
    * 
    */ 
    @XmlElementDecl(namespace = "http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0", name = "archetype-catalog") 
    public JAXBElement<ArchetypeCatalog> createArchetypeCatalog(ArchetypeCatalog value) { 
     return new JAXBElement<ArchetypeCatalog>(_ArchetypeCatalog_QNAME, ArchetypeCatalog.class, null, value); 
    } 

} 

然而,當實際上unmashalling example文件進行測試,我得到以下幾點:

堆棧跟蹤:

Exception in thread "main" java.lang.RuntimeException: an error occurred while unmarshalling xml into com.catalogupdater.plugin.jaxb.ArchetypeCatalog object 
    at com.catalogupdater.plugin.converter.JAXBConverter.stringToObject(JAXBConverter.java:48) 
    at Main.main(Main.java:60) 
Caused by: javax.xml.bind.UnmarshalException: unexpected element (uri:"http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0", local:"archetype-catalog"). Expected elements are (none) 

任何建議是怎麼回事錯在這裏? 親切的問候

編輯: 下面是我使用的是全解組邏輯:

public static <T> T stringToObject(final String textClazz, final Class<T> clazz) 
    { 
     T returnedValue = null; 
     try 
     { 
     final JAXBContext jaxbContext = JAXBContext.newInstance(clazz); 
     final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 
     final StringReader reader = new StringReader(textClazz); 
     returnedValue = (T) unmarshaller.unmarshal(reader); 
     } 
     catch (final JAXBException e) 
     { 
     throw new RuntimeException(
       "an error occurred while unmarshalling xml into " + clazz.getCanonicalName() + " object", e); 
     } 
     return returnedValue; 
    } 
+0

顯示完整的反編組代碼。 – lexicore

+0

@lexicore嗨,我編輯了這個問題 – Moonlit

+0

不知怎的,你的'ObjectFactory'沒有被使用。嘗試使用包名稱('clazz.getPackage()。getName()')創建'JAXBContext'。 – lexicore

回答

2

你應該這樣做:

 final JAXBContext jaxbContext = JAXBContext.newInstance(clazz.getPackage().getName()); 
    final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); 
    final StringReader reader = new StringReader(textClazz); 
    returnedValue = (T) unmarshaller.unmarshal(reader).getValue(); 

很顯然,如果你只是創建clazzJAXBContext,該ObjectFactory不考慮。 ObjectFactory是一個所謂的「XML註冊表」,它說明哪個類應該用於哪個根元素。

從反編組獲得的結果是JAXBContext<SomeType>,它包含類型SomeType(在您的情況下爲ArchetypeCatalog)的值以及根元素的名稱。您可以通過getValue()獲得您感興趣的價值。

你在答案中所做的工作也有效,但這不是「JAXB方式」。

您已經手動添加了@XmlRootElement註釋,這對於生成的代碼肯定不適用。你可以通過像jaxb2-annotate-plugin這樣的插件添加它(免責聲明:我是作者)。

但最終你應該更好地使用ObjectFactory,因爲它是它的用途。長期堅持標準模式會更好。

+1

這當然是更好的解決方案和正確的答案。我已經嘗試了你的建議,它工作。對於其他方向(編組),但它不能正常工作,說有一個缺少@RootElement註釋。我發現我不得不使用'ObjectFactory'來將根類包裝到一個帶有所需信息的JAXBElement中。這也有效。但是我注意到xsi:schemaLocation在生成的xml中缺失。你有任何建議如何也實現這一點(除了手動添加schemalocation,因爲我現在做) – Moonlit

1

我已經想通了,有以下@RootElement註釋在生成的ArchetypeCatalog類丟失:

@XmlRootElement(namespace = "http://maven.apache.org/plugins/maven-archetype-plugin/archetype-catalog/1.0.0", name = "archetype-catalog") 
@XmlAccessorType(XmlAccessType.FIELD) 
@XmlType(name = "ArchetypeCatalog", propOrder = { 

}) 
public class ArchetypeCatalog 
{ 

... 
} 

我已經手動添加它,現在它工作正常。不知道爲什麼這不是生成的。儘管如此,畢竟我認爲從xsd規範生成類需要謹慎對待。

親切的問候

編輯:如在評論@ulab說,失蹤的@RootElement的原因給出here

編輯:此外,手動添加@XMLRootElement註釋並不是必要或不可取的。更多細節可以在@lexicor寫的答案中找到。

+1

現在你知道[爲什麼](https://community.oracle.com/blogs/kohsuke/2006/03/03/why-does-jaxb-put-xmlrootelement-sometimes-not-always) – ulab

+0

@ulab謝謝你: )現在很清楚 – Moonlit