Сортировка и отмена сортировки Java

#java #xml #jaxb #marshalling #unmarshalling

#java #xml #jaxb #сортировка #отмена сортировки

Вопрос:

Employee.xsd

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" jxb:version="1.0" elementFormDefault="qualified">
<xsd:include schemaLocation="Family.xsd"/>
    <xsd:element name="NewFields">
        <xsd:complexType>
            <xsd:sequence>
                <xsd:element name="empFirstName" type="xsd:string" />
                <xsd:element name="empLastName" type="xsd:string" />
                <xsd:element name="family" type="FamilyFields" nillable="true" maxOccurs="unbounded" minOccurs="0"/>
            </xsd:sequence>
        </xsd:complexType>
    </xsd:element>
</xsd:schema>
  

Family.xsd

 <?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jxb="http://java.sun.com/xml/ns/jaxb" jxb:version="1.0" elementFormDefault="qualified">
<xsd:complexType name="FamilyFields">
        <xsd:sequence>
            <xsd:element name="relation" type="xsd:string" />
            <xsd:element name="firstName" type="xsd:string" />
            <xsd:element name="lastName" type="xsd:string"/>
        </xsd:sequence>
</xsd:complexType>  
</xsd:schema>
  

Стороннее приложение, которое использует эти 2 схемы, генерирует строку xml, например —

 <NewFields>
    <empFirstName>Kevin</empFirstName>
    <empLastName>Smith</empLastName>
    <family>
        <FamilyFields>
            <relation>self</relation>
            <firstName>New Kevin</firstName>
            <lastName>New Smith</lastName>
        </FamilyFields>
        <FamilyFields>
            <relation>wife</relation>
            <firstName>Jennifer</firstName>
            <lastName>Smith</lastName>
        </FamilyFields>
    </family>
</NewFields>
  

Вторая схема всегда является фиксированной схемой.

Мое требование состоит в том, чтобы проанализировать тег отношения, и если отношение является «self», мне нужно перезаписать empFirstName и empLastName на FirstName и LastName соответствующих полей.

Как я могу этого добиться?

РЕДАКТИРОВАТЬ 1: Employee.xsd является динамическим и может быть чем угодно. Но Family.xsd является статическим и может быть импортирован из любого другого xsd.

Ответ №1:

Общая схема: (а) сопоставьте файлы схемы XML, (б) отмените маршалирование данного XML, (в) измените объект XML в памяти, наконец (г) маршалируйте измененный объект в любом месте, где вы хотите.

Сопоставьте ваши файлы XML-схемы

 @XmlRootElement(name = "FamilyFields") public class FamilyFields {

  @XmlElement public String relation;
  @XmlElement public String firstName;
  @XmlElement public String lastName;

  public FamilyFields() {}
}

@XmlRootElement(name = "NewFields") public class NewFields {

  @XmlElement public String empFirstName;
  @XmlElement public String empLastName;
  @XmlElementWrapper(name = "family")
  @XmlElement(name = "FamilyFields")
  public List<FamilyFields> familyFields;

  public NewFields() {}
}
  

(Если вы прислушаетесь к совету: сделайте это вручную! Генерация объектов JAXB с помощью XJC почти никогда не выдает ожидаемых результатов и может занять много времени, если у вас нет под рукой очень простых файлов схемы.)

Получение JAXBContext Unmarshaller и Marshaller

 JAXBContext context = JAXBContext.newInstance(NewFields.class, FamilyFields.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Marshaller marshaller = context.createMarshaller();
// set optional properties
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
  

Обработка входящего XML

 // the XML content you gave
String xml = ...

StringReader reader = new StringReader(xml);
NewFields newFields = (NewFields) unmarshaller.unmarshal(reader);

// modify the unmarshalled data to your heart's content
newFields.empLastName = ...

// marshal the modified data anywhere you want
marshaller.marshal(newFields, System.out);
  

Комментарии:

1. если в моем xml есть массив FamilyFields, похоже, он не работает! Кроме того, я вижу некоторое исключение с приведенным выше кодом … что-то вроде — javax.xml.bind . Исключение UnmarshalException: неожиданный элемент (uri: «», локальный: «семейство»). Ожидаемые элементы (неизвестны)

2. Я скопировал ваши два объявления схемы и протестировал XML, и они работали для меня. Если вы получаете unexpected element исключение, возможно, XML, который вы пытаетесь отменить маршаллинг / маршаллинг, имеет объявления пространства имен XML. Это может быть проблемой. (Если вы разместите свой XML где-нибудь, например, в pastebin, я могу взглянуть на него.)

3. Кстати, я использовал JAXB 2.2.4-1 в своих тестах.

4. Вы правы, я пропустил добавление аннотации XmlRootElement в класс FamilyFields! Спасибо!

Ответ №2:

Если у вас есть XSD, то манипулировать XML проще всего с помощью привязки данных XML. Используя XSD, вы можете создавать классы, подобные Java bean, которые представляют XSD. Теперь вы можете использовать методы получения и установки в классе Java, а затем выводить XML. Существует множество решений для привязки XML-данных. Попробуйте XML-компоненты:

http://xmlbeans.apache.org/