JAXB过滤了解析
我正在使用JAXB来解析基于GWT的应用程序中的XML文件。 XML看起来像这样(一个简化的例子):
... ... ... ... ... ... ... ... ... ... ... ... ... ...
我已经定义了类,如下所示:
@XmlRootElement(name="addressbook") public class Addressbook implements Serializable { private ArrayList companyList = new ArrayList(); public Addressbook() { } @XmlElement(name = "company") public ArrayList getCompanyList() { return companyList; } } ============================= @XmlRootElement(name="company") public class Company implements Serializable { private String name; private ArrayList contactList = new ArrayList(); public Company() { } @XmlAttribute public String getName() { return name; } @XmlElement(name = "contact") public ArrayList 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文件,然后手动过滤记录。 但是如果输入文件很大,那么解析我需要的东西可能更有效。 那么是否可以预先指定一个标准并仅解析特定记录?
谢谢。
您可以使用EclipseLink JAXB(MOXy )中的@XmlPath扩展来处理这种情况(我是MOXy技术主管):
@XmlRootElement(name="addressbook") public class Addressbook implements Serializable { private ArrayList companyList = new ArrayList (); public Addressbook() { } @XmlPath("company[@name='abc']") public ArrayList 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; } }
你可以
- 将XSLT转换应用于XML文件,或
- 将文件解组为DOM,并使用XPath选择所需的节点
在将生成的对象传递给unmarshal方法之前
但是,创建一个由公司名称键入的内存Map
可能更简单:
public class SearchableAddressBook { public final Map companyMap = new HashMap(); public SearchableAddressBook(List companyList) { for (Company company: companyList) { companyMap.add(company.getName(), company)); } }
或者如果你真的想要过度设计它,可以创建一个内存数据库。