JAXB связывание 3 уровня вложенных элементов - PullRequest
2 голосов
/ 13 июня 2019

Я пытаюсь привязать следующий xml к java, используя jaxb

<Validation> 
...
        <Options>
             <AllowUnspecifiedParameters>
                  <Header> True </Header>
                  <Query> True </Query>
                  <Cookies> True </Cookies>
             </AllowUnspecifiedParameters>
        </Options>
</Validation> 

Я видел такой же пример, как JAXB-привязка вложенных элементов Но самый глубокий вложенный уровень для списка,@XmlElementWrapper предназначен только для коллекций, поэтому, похоже, он не подходит под мой случай.

Кто-нибудь знает, как я могу это сделать?Очень ценю это.

Ответы [ 3 ]

1 голос
/ 20 июня 2019

Вы можете использовать @XmlAnyElement для предоставления вложенных элементов, хотя они возвращаются в довольно сыром виде - как org.w3c.dom.Element экземпляры:

@XmlRootElement(name = "Validation")
public class Validation {
    private List<Element> options;

    @XmlElementWrapper(name = "Options")
    @XmlAnyElement
    public List<Element> getOptions() {
        return options;
    }

    ...
}

Затем данные можно детализировать в:

    Validation validation = (Validation) unmarshaller.unmarshal(source);
    for (Element element : validation.getOptions()) {
        System.out.println(element.getNodeName() + ":");
        NodeList childNodes = element.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node childNode = childNodes.item(i);
            if (childNode.getNodeType() == Node.ELEMENT_NODE)
                System.out.println("  " + childNode.getNodeName() + "=" +
                        childNode.getTextContent());
        }
    }

Который показывает все данные, поступающие через:

AllowUnspecifiedParameters:
  Header= True 
  Query= True 
  Cookies= True 
1 голос
/ 19 июня 2019

Опция 1 Один из простых способов сделать это с помощью JaxB - определить свой адаптер для элемента Options. Адаптер используется для более или менее превращения любого XML в любой объект и наоборот (пользовательский маршалинг).

    @XmlJavaTypeAdapter(OptionsAdapter.class)

    public class OptionsAdapter extends extends XmlAdapter<Element, Options> {

    @Override
        public Element marshal(Options v) throws Exception {
            // put your marshaling logic here
        }

        @Override
        public Options unmarshal(Element node) throws Exception {
           // put your unmarshaling logic here
        }

    }

Then in the class holding the options element you will have:

    public class ClazzHoldingOptions {

      @XmlJavaTypeAdapter(OptionsAdapter.class)
      private Options options;

    }

Опция 2 EclipseLink имеет функцию отображения элементов с помощью выражений xpath

     @XmlPath("AllowUnspecifiedParameters/Header/text()")
     private String  header;

https://www.eclipse.org/eclipselink/api/2.4/org/eclipse/persistence/oxm/annotations/XmlPath.html

Вариант 3 При чтении кода @ df778899 я думаю, что его решение не оптимально, но оно решает проблему, которую я до сих пор не рассматривал. И когда у вас так много атрибутов, что вы на самом деле не хотите их отображать, или если вы просто не контролируете содержимое XML, не доверяете ему и не хотите вносить изменения. В котором я бы просто отобразил HashMap:

    @XmlJavaTypeAdapter(OptionsAdapter.class)

    public class OptionsAdapter extends extends XmlAdapter<Element, Options> {

    @Override
        public Element marshal(Hashmap v) throws Exception {
            // put your marshaling logic here
        }

        @Override
        public HashMap unmarshal(Element node) throws Exception {
           // put your unmarshaling logic here
        }

    }

Then in the class holding the options element you will have:

    public class ClazzHoldingOptions {

      @XmlJavaTypeAdapter(OptionsAdapter.class)
      private HashMap options;

    }

Резюме. Итак, позвольте мне обобщить плюсы и минусы

Вариант 1. + Стандартный Aproach pure jaxB + Хорошо, если у вас есть контроль над собственной схемой XML-файла. Или, если не ожидается, что схема будет меняться каждый месяц. -Плохо, если схема или XML-файл очень изменчивы.

Вариант 2. + Чрезвычайно прост в использовании. Нет необходимости в адаптерах. - Снова не оптимальное решение, если ваша схема изменчива. Требует конкретной реализации JaxB

Вариант 3. -Только хорошо, если у вас есть нестабильный XML для избежания критических изменений.

PS: Единственный случай, когда я использовал бы что-то вроде решения @ df778899, - это крайняя структурная неопределенность того, что будет в XML. Например, если я знаю, что что-то придет в XML, но я не знаю, где именно. PLus это нехватка памяти, вы хотите хранить в памяти все метаданные, относящиеся к вашему xml.

0 голосов
/ 22 июня 2019

Оказывается, мой вопрос выше имеет простой ответ:

XML:

<Validation> 
...
        <Options>
             <AllowUnspecifiedParameters>
                  <Header> True </Header>
                  <Query> True </Query>
                  <Cookies> True </Cookies>
             </AllowUnspecifiedParameters>
        </Options>
</Validation> 

Объект Java:

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

  // some more fields
  // ...


  private Options option = new Options();

  @XmlElement(name = "Options")
  public Options getOptions() {
    return options;
  }

}

public class Options {

  @XmlElement(name = "AllowUnspecifiedParameters")
  public StrictOptions allowUnspecifiedParameters = new StrictOptions();

  public static class StrictOptions {
    @XmlElement(name = "Header")
    public boolean header = true;

    @XmlElement(name = "Query")
    public boolean query = true;

    @XmlElement(name = "Cookie")
    public boolean cookie = true;

  }
}

Но если у вас действительно сложная XML-схема или структура Java-объекта, как предложили @ df778899 и @Alexandar Petrov, XmlAdapter и @ XmlAnyElement - мощные инструменты.

Вот один пример, который я нашел: Отображение произвольного списка объектов с использованием @XmlAnyElement и XmlAdapter JAXB

...