2011-05-10 64 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