JAXB фильтрует разбор - PullRequest
       20

JAXB фильтрует разбор

9 голосов
/ 10 мая 2011

Я использую JAXB для анализа XML-файла в моем приложении на основе GWT.XML выглядит следующим образом (упрощенный пример):

<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-файл, а затем вручную отфильтровать записи.Но если входной файл большой, может быть эффективнее разобрать только то, что мне нужно.Так можно ли задавать критерий заранее и анализировать только конкретные записи?

Спасибо.

Ответы [ 2 ]

10 голосов
/ 10 мая 2011

Вы можете использовать расширение @XmlPath в EclipseLink JAXB (MOXy ), чтобы справиться с этим делом (я технический руководитель MOXy):

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

}
1 голос
/ 10 мая 2011

Вы можете либо

  • Применить XSLT-преобразование к файлу XML, либо
  • Удалить файл в DOM и использовать XPath для выбора нужных узлов

перед передачей результирующих объектов в метод unmarshal

Возможно, было бы проще создать в памяти 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));
        }

}

Или создайте БД в памяти, если вы действительно хотите перегрузить ее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...