2011-05-10 38 views
9

我正在使用JAXB在我的基於GWT的應用程序中解析XML文件。的XML看起來像這樣(簡化的例子):JAXB過濾解析

<addressbook> 

    <company name="abc"> 
     <contact> 
      <name>...</name> 
      <address>...</address> 
     </contact> 

     <contact> 
      <name>...</name> 
      <address>...</address> 
     </contact> 

     <contact> 
      <name>...</name> 
      <address>...</address> 
     </contact> 
     ... 
     ... 
    </company> 

    <company name="def"> 
     <contact> 
      <name>...</name> 
      <address>...</address> 
     </contact> 
     ... 
     ... 
    </company> 

    ... 
    ... 

</addressbook> 

我已經定義的類,如下所示:

@XmlRootElement(name="addressbook") 
public class Addressbook implements Serializable { 

    private ArrayList<Company> companyList = new ArrayList<Company>(); 

    public Addressbook() {    
    } 

    @XmlElement(name = "company") 
    public ArrayList<Company> getCompanyList() { 
     return companyList; 
    } 


} 

============================= 

@XmlRootElement(name="company") 
public class Company implements Serializable { 

    private String name; 

    private ArrayList<Contact> contactList = new ArrayList<Contact>(); 

    public Company() {  
    } 

    @XmlAttribute 
    public String getName() { 
     return name; 
    } 

    @XmlElement(name = "contact") 
    public ArrayList<Contact> getContactList() { 
     return contactList; 
    } 

    ... 
    ... 
} 

============================= 

@XmlRootElement(name="contact") 
public class Contact implements Serializable 
{ 
    private String name; 
    private String address; 

    public Contact() { 
    } 

    @XmlElement 
    public String getName() 
    { 
     return name; 
    } 

    @XmlElement 
    public String getAddress() 
    { 
     return address; 
    } 

    ... 
    ... 
} 

這是代碼:

try { 
    JAXBContext jc = JAXBContext.newInstance(Addressbook.class); 
    Unmarshaller um = jc.createUnmarshaller(); 
    addressbook = (Addressbook) um.unmarshal(new FileReader("ds/addressbook.xml"));   
} catch (JAXBException e) { 
    e.printStackTrace(); 
} 

我需要根據公司名稱獲取聯繫人列表。例如,獲取公司「abc」的所有聯繫人。我可以解析整個XML文件,然後手動過濾記錄。但是如果輸入文件很大,解析我所需要的可能會更有效率。那麼是否可以預先指定標準並僅解析特定記錄?

謝謝。

回答

1

你既可以

  • 應用XSLT轉換XML文件,或
  • 解組文件到DOM,並使用XPath選擇通過之前,你要

節點所產生的對象到解組方法

儘管如此,創建一個內存爲Map的公司名稱爲:

public class SearchableAddressBook { 

    public final Map<String, Company> companyMap = new HashMap<String,Company>(); 

    public SearchableAddressBook(List<Company> companyList) { 
     for (Company company: companyList) { 
      companyMap.add(company.getName(), company)); 
     } 

} 

或者如果您真的想過度設計內存數據庫,請創建內存數據庫。

+0

感謝你的迴應。你可以使用這些方法更簡單的方式來展示(或指向我)示例代碼嗎?對不起,我還是這個東西的新手。 – DFB 2011-05-10 12:56:23

+0

更新了我的答案,儘管Map方法仍然解析整個XML文件,所以它可能不是您要查找的內容。記住要測量各種數據集的性能! – artbristol 2011-05-10 13:20:48

+0

您是否建議通過修改我的地址簿類,解組會將數據轉化爲地圖(實際上這會很棒)?或者我應該創建一個新的類SearchableAddressBook將列表轉換爲映射「之後」解組?謝謝。 – DFB 2011-05-10 13:59:51

10

你可以使用EclipseLink JAXB (MOXy的@XmlPath擴展)來處理這種情況(我是莫西技術主管):

@XmlRootElement(name="addressbook") 
public class Addressbook implements Serializable { 

    private ArrayList<Company> companyList = new ArrayList<Company>(); 

    public Addressbook() {    
    } 

    @XmlPath("company[@name='abc']") 
    public ArrayList<Company> getCompanyList() { 
     return companyList; 
    } 


} 

更多信息:


更新 - 使用StreamFilter

下面的例子演示了一個StreamFilter可以如何利用這個用例:

import java.io.FileInputStream; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 
import javax.xml.stream.XMLInputFactory; 
import javax.xml.stream.XMLStreamReader; 

public class Demo { 

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

     XMLInputFactory xif = XMLInputFactory.newFactory(); 
     FileInputStream xmlStream = new FileInputStream("input.xml"); 
     XMLStreamReader xsr = xif.createXMLStreamReader(xmlStream); 
     xsr = xif.createFilteredReader(xsr, new CompanyFilter()); 

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     Addressbook addressbook = (Addressbook) unmarshaller.unmarshal(xsr); 

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

的StreamFilter的實現如下:

import javax.xml.stream.StreamFilter; 
import javax.xml.stream.XMLStreamReader; 

public class CompanyFilter implements StreamFilter { 

    private boolean accept = true; 

    public boolean accept(XMLStreamReader reader) { 
     if(reader.isStartElement() && "company".equals(reader.getLocalName())) { 
      accept = "abc".equals(reader.getAttributeValue(null, "name")); 
     } else if(reader.isEndElement()) { 
      boolean returnValue = accept; 
      accept = true; 
      return returnValue; 
     } 
     return accept; 
    } 

} 
+0

巧合的是,當您發佈您的回覆時,我正在閱讀您的博客的想法。我認爲這是我正在尋找的,但如果可能的話,我真的更願意避免使用額外的庫。否則,我會考慮使用MOXY。另一方面,我可以將它們解組爲一個Map,而不是解組列表中的公司對象嗎? – DFB 2011-05-10 14:29:00

+0

@DFB - 您可以將公司對象解組爲映射(http://bdoughan.blogspot.com/2010/09/processing-atom-feeds-with-jaxb.html)。如果可能可以使用StreamFilter來獲取所需的行爲(http://download.oracle.com/javase/6/docs/api/javax/xml/stream/XMLInputFactory.html#createFilteredReader(javax.xml.stream) .XMLStreamReader,%20javax.xml.stream.StreamFilter),使用標準的JAXB API。 – 2011-05-10 15:00:31

+0

感謝您的迴應。我會研究StreamFilter。關於解組映射,我不得不承認,我無法它從你的博客發佈出來,我想我還有很多東西要學,甚至在我開始發佈問題之前:) – DFB 2011-05-10 15:22:30