JAXB filtered parsing

You could use the @XmlPath extension in EclipseLink JAXB (MOXy) to handle this case (I'm the MOXy tech lead):

@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;
    }


}

For More Information:

  • http://bdoughan.blogspot.com/2011/03/map-to-element-based-on-attribute-value.html

UPDATE - Using StreamFilter

The example below demonstrates how a StreamFilter could be leveraged for this use case:

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);
    }
}

The implementation of the StreamFilter is as follows:

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;
    }

}

You could either

  • Apply an XSLT transformation to the XML file, or
  • Unmarshall the file into a DOM, and use XPath to select the nodes you want

before passing the resulting object(s) to the unmarshal method

It might be simpler though, to create an in-memory Map keyed by company name:

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));
        }

}

Or create an in-memory DB if you really want over-engineer it.