2011-09-28 6 views

Odpowiedz

11

można wykorzystać koncepcję JAXB na XmlAdapter zrobić coś jak następuje:

input.xml

Poniżej znajduje się dokument XML Użyję do tego przykładu. The 3rd phone-number wpis jest nawiązaniem do 1 phone-number wpisu, a 5th phone-number wpis jest nawiązaniem do 4 .:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<customer> 
    <phone-number id="A"> 
     <number>555-AAAA</number> 
    </phone-number> 
    <phone-number id="B"> 
     <number>555-BBBB</number> 
    </phone-number> 
    <phone-number id="A"/> 
    <phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"> 
     <number>555-WORK</number> 
     <extension>1234</extension> 
    </phone-number> 
    <phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"/> 
</customer> 

klientów

Klasa klient utrzymuje kolekcję PhoneNumber obiektów. To samo wystąpienie numeru PhoneNumber może pojawić się wiele razy w kolekcji.

package forum7587095; 

import java.util.List; 

import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement 
public class Customer { 

    private List<PhoneNumber> phoneNumbers; 

    @XmlElement(name="phone-number") 
    public List<PhoneNumber> getPhoneNumbers() { 
     return phoneNumbers; 
    } 

    public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) { 
     this.phoneNumbers = phoneNumbers; 
    } 

} 

PhoneNumber

Jest to klasa, która może pojawić się zarówno w samym dokumencie lub jako odniesienie. Będzie to obsługiwane przy użyciu XmlAdapter. XmlAdapter jest skonfigurowany przy użyciu adnotacji @XmlJavaTypeAdapter. Ponieważ mamy określony adaptera na poziomie typu/klasy będzie ona miała zastosowanie do wszystkich właściwości odwołujących klasę PhoneNumber:

package forum7587095; 

import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 

@XmlJavaTypeAdapter(PhoneNumberAdapter.class) 
public class PhoneNumber { 

    private String id; 
    private String number; 

    public String getId() { 
     return id; 
    } 

    public void setId(String id) { 
     this.id = id; 
    } 

    public String getNumber() { 
     return number; 
    } 

    public void setNumber(String number) { 
     this.number = number; 
    } 

    @Override 
    public boolean equals(Object arg0) { 
     if(null == arg0 || arg0.getClass() != this.getClass()) { 
      return false; 
     } 
     PhoneNumber test = (PhoneNumber) arg0; 
     if(!equals(id, test.getId())) { 
      return false; 
     } 
     return equals(number, test.getNumber()); 
    } 

    protected boolean equals(String control, String test) { 
     if(null == control) { 
      return null == test; 
     } else { 
      return control.equals(test); 
     } 
    } 

    @Override 
    public int hashCode() { 
     return id.hashCode(); 
    } 

} 

WorkPhoneNumber

Oparte na Twój komentarz dodałem podklasę PhoneNumber.

package forum7587095; 

public class WorkPhoneNumber extends PhoneNumber { 

    private String extension; 

    public String getExtension() { 
     return extension; 
    } 

    public void setExtension(String extension) { 
     this.extension = extension; 
    } 

    @Override 
    public boolean equals(Object arg0) { 
     if(!super.equals(arg0)) { 
      return false; 
     } 
     return equals(extension, ((WorkPhoneNumber) arg0).getExtension()); 
    } 

} 

PhoneNumberAdapter

Poniżej jest realizacja XmlAdapter. Zauważ, że musimy zachować, jeśli obiekt PhoneNumber był wcześniej widziany. Jeśli tak jest, wypełniamy tylko część obiektu id obiektu .

package forum7587095; 

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 

import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlSeeAlso; 
import javax.xml.bind.annotation.XmlType; 
import javax.xml.bind.annotation.adapters.XmlAdapter; 

public class PhoneNumberAdapter extends XmlAdapter<PhoneNumberAdapter.AdaptedPhoneNumber, PhoneNumber>{ 

    private List<PhoneNumber> phoneNumberList = new ArrayList<PhoneNumber>(); 
    private Map<String, PhoneNumber> phoneNumberMap = new HashMap<String, PhoneNumber>(); 

    @XmlSeeAlso(AdaptedWorkPhoneNumber.class) 
    @XmlType(name="phone-number") 
    public static class AdaptedPhoneNumber { 
     @XmlAttribute public String id; 
     public String number; 

     public AdaptedPhoneNumber() { 
     } 

     public AdaptedPhoneNumber(PhoneNumber phoneNumber) { 
      id = phoneNumber.getId(); 
      number = phoneNumber.getNumber(); 
     } 

     public PhoneNumber getPhoneNumber() { 
      PhoneNumber phoneNumber = new PhoneNumber(); 
      phoneNumber.setId(id); 
      phoneNumber.setNumber(number); 
      return phoneNumber; 
     } 

    } 

    @XmlType(name="work-phone-number") 
    public static class AdaptedWorkPhoneNumber extends AdaptedPhoneNumber { 

     public String extension; 

     public AdaptedWorkPhoneNumber() { 
     } 

     public AdaptedWorkPhoneNumber(WorkPhoneNumber workPhoneNumber) { 
      super(workPhoneNumber); 
      extension = workPhoneNumber.getExtension(); 
     } 

     @Override 
     public WorkPhoneNumber getPhoneNumber() { 
      WorkPhoneNumber phoneNumber = new WorkPhoneNumber(); 
      phoneNumber.setId(id); 
      phoneNumber.setNumber(number); 
      phoneNumber.setExtension(extension); 
      return phoneNumber; 
     } 
} 

    @Override 
    public AdaptedPhoneNumber marshal(PhoneNumber phoneNumber) throws Exception { 
     AdaptedPhoneNumber adaptedPhoneNumber; 
     if(phoneNumberList.contains(phoneNumber)) { 
      if(phoneNumber instanceof WorkPhoneNumber) { 
       adaptedPhoneNumber = new AdaptedWorkPhoneNumber(); 
      } else { 
       adaptedPhoneNumber = new AdaptedPhoneNumber(); 
      } 
      adaptedPhoneNumber.id = phoneNumber.getId(); 
     } else { 
      if(phoneNumber instanceof WorkPhoneNumber) { 
       adaptedPhoneNumber = new AdaptedWorkPhoneNumber((WorkPhoneNumber)phoneNumber); 
      } else { 
       adaptedPhoneNumber = new AdaptedPhoneNumber(phoneNumber); 
      } 
      phoneNumberList.add(phoneNumber); 
     } 
     return adaptedPhoneNumber; 
    } 

    @Override 
    public PhoneNumber unmarshal(AdaptedPhoneNumber adaptedPhoneNumber) throws Exception { 
     PhoneNumber phoneNumber = phoneNumberMap.get(adaptedPhoneNumber.id); 
     if(null != phoneNumber) { 
      return phoneNumber; 
     } 
     phoneNumber = adaptedPhoneNumber.getPhoneNumber(); 
     phoneNumberMap.put(phoneNumber.getId(), phoneNumber); 
     return phoneNumber; 
    } 

} 

Demo

Aby zapewnić tę samą instancję XmlAdapter służy do całych marshal i unmarshal operacji musimy szczegółowo określone wystąpienie XmlAdapter zarówno na Marshaller i Unmarshaller:

package forum7587095; 

import java.io.File; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Marshaller; 
import javax.xml.bind.Unmarshaller; 

public class Demo { 

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

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     unmarshaller.setAdapter(new PhoneNumberAdapter()); 
     File xml = new File("src/forum7587095/input.xml"); 
     Customer customer = (Customer) unmarshaller.unmarshal(xml); 

     System.out.println(customer.getPhoneNumbers().get(0) == customer.getPhoneNumbers().get(2)); 
     System.out.println(customer.getPhoneNumbers().get(3) == customer.getPhoneNumbers().get(4)); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.setAdapter(new PhoneNumberAdapter()); 
     marshaller.marshal(customer, System.out); 
    } 

} 

Wyjście

true 
true 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<customer> 
    <phone-number id="A"> 
     <number>555-AAAA</number> 
    </phone-number> 
    <phone-number id="B"> 
     <number>555-BBBB</number> 
    </phone-number> 
    <phone-number id="A"/> 
    <phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"> 
     <number>555-WORK</number> 
     <extension>1234</extension> 
    </phone-number> 
    <phone-number xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="work-phone-number" id="W"/> 
</customer> 

Aby uzyskać więcej informacji

+0

Dzięki Blaise za bardzo szczegółową odpowiedź! Czy to pojęcie jest takie samo, jeśli "PhoneNumber" ma podklasy? Na przykład "Klient" ma wiele odniesień do tej samej instancji podklasy 'Numer_telefonu'? – holic87

+1

@ holic87 - Zaktualizowałem swoją odpowiedź, aby 'PhoneNumber' miał podklasy. –

+0

Dzięki za wyjaśnienie! – holic87

Powiązane problemy