Как я могу создать класс, из которого я могу получить XML узла в виде строки

Вот описание элемента configuration, извлеченного из модели POM Apache Maven 4.0.0. xsd.

<xs:element minOccurs="0" name="configuration">
  <xs:annotation>
    <xs:documentation source="version">0.0.0+</xs:documentation>
    <xs:documentation source="description">
      <p>The configuration as DOM object.</p> <p>By default, every element content is trimmed, but starting with Maven 3.1.0, you can add <code>xml:space="preserve"</code> to elements you want to preserve whitespace.</p> <p>You can control how child POMs inherit configuration from parent POMs by adding <code>combine.children</code> or <code>combine.self</code> attributes to the children of the configuration element:</p> <ul> <li><code>combine.children</code>: available values are <code>merge</code> (default) and <code>append</code>,</li> <li><code>combine.self</code>: available values are <code>merge</code> (default) and <code>override</code>.</li> </ul> <p>See <a href="http://maven.apache.org/pom.html#Plugins">POM Reference documentation</a> and <a href="http://plexus.codehaus.org/plexus-utils/apidocs/org/codehaus/plexus/util/xml/Xpp3DomUtils.html">Xpp3DomUtils</a> for more information.</p>
    </xs:documentation>
  </xs:annotation>
  <xs:complexType>
    <xs:sequence>
      <xs:any minOccurs="0" maxOccurs="unbounded" processContents="skip"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>

Я использую следующий файл привязок для создания классов из приведенного выше xsd:

<jxb:bindings version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
  jxb:extensionBindingPrefixes="xjc" 
  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">

  <jxb:globalBindings>
    <!-- use plural method names for repeatable elements -->
    <xjc:simple />
  </jxb:globalBindings>

  <jxb:bindings schemaLocation="maven-4.0.0.xsd">
    <!-- rename all the node of type "any" to "elements" to improve readability -->
    <jxb:bindings multiple="true" node="//xs:any" >
      <jxb:property name="elements"/>
    </jxb:bindings>
  </jxb:bindings>
</jxb:bindings>

Это прекрасно работает. Например, он создает класс Configuration с методом getElements(), который возвращает Element экземпляров.

Однако, когда я сталкиваюсь с тегом configuration, я хочу, чтобы сгенерированный класс Configuration мог хранить XML всех базовых элементов в виде строки (как это было написано в файле XML синтаксического анализатора, сохраняя комментарии, новые строки, пустые строки и пробелы .)

Например, давайте представим, что у меня есть следующий файл XML:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>test</groupId>
  <artifactId>test</artifactId>
  <version>1.0.1-SNAPSHOT</version>
  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>${plugin.maven-compiler-plugin.version}</version>
          <configuration>
            <source>${build.jdk.source.version}</source>
              <target>${build.jdk.target.version}</target>
            <encoding>${project.build.sourceEncoding}</encoding>
                  <fork>true</fork>
          </configuration>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

После анализа этого XML-файла и загрузки его в мою сгенерированную модель я хотел бы иметь возможность вызывать метод getXML() для экземпляра Configuration и получать:

<configuration>
  <source>${build.jdk.source.version}</source>
    <target>${build.jdk.target.version}</target>
  <encoding>${project.build.sourceEncoding}</encoding>
        <fork>true</fork>
</configuration>

(неправильный отступ сохраняется как есть)

Я думал о следующем подходе

  1. обнаружить в моем файле привязок, что я обрабатываю узел "конфигурация" (как?)
  2. заставить класс Configuration расширить класс XmlHolder, способный хранить XML в виде строки (с методами getDom() и setXml(String))
  3. используйте класс адаптера XmlHolderAdapter, чтобы извлечь фрагмент XML в виде строки и установить его в классе Configuration.

Мои вопросы:

  • подход правильный?
  • есть ли лучший подход?
  • Как я могу изменить свой файл привязок и каким должно быть содержимое моего класса адаптера для достижения этого (если я не ошибаюсь, я получаю XMLStreamReader в качестве источника)?

Заранее большое спасибо,


person Kraal    schedule 14.02.2017    source источник


Ответы (1)


Я также в прошлом искал ответ на аналогичный вопрос и нуждался в соответствующей XSD-части класса во время выполнения. В конце концов я написал для этого xjc-documentation-annotation-plugin.

Как обычно его использовать, вы можете увидеть в этом ответе: Как сделать так, чтобы сгенерированные классы содержали Javadoc из документации XML Schema

Я также готовлю пример и тестирую для вас конкретный вопрос. Посмотрите коммит, например gradle project.

Для полного понимания пошагово:

  1. В gradle я использую gradle-xjc-plugin для вызова XJC (вы можете использовать аналогичный maven плагин или вызовите его напрямую):
plugins {
    id 'java'
    id 'org.unbroken-dome.xjc' version '1.4.1' // https://github.com/unbroken-dome/gradle-xjc-plugin
}

dependencies {
    xjcClasspath 'info.hubbitus:xjc-documentation-annotation-plugin:1.0'
    ...
}
// Results by default in `build/xjc/generated-sources`
xjcGenerate {
    /**
     * There:
     * 1. CadastralBlock.xsd is minimal example of functional.
     * 2. maven-4.0.0.xsd - example by SOq https://stackoverflow.com/questions/42223784/how-can-i-generate-a-class-from-which-i-can-retrieve-the-xml-of-a-node-as-a-stri
     */
    source = fileTree('src/main/resources') { include '*.xsd' }
    bindingFiles = fileTree('src/main/jaxb') { include '*.xjb' }
    outputDirectory = file('src/main/generated-java')
    packageLevelAnnotations = false
    targetPackage = 'info.hubbitus.xjc.plugin.example'
    extraArgs = [ '-XPluginDescriptionAnnotation' ]
}
  1. Я также добавляю сгенерированные классы в исходный путь:
sourceSets.main.java.srcDir new File(buildDir, xjcGenerate.outputDirectory.absolutePath)
// If you use IntellyJ Idea:
idea {
    module {
        // Marks the already(!) added srcDir as "generated"
        generatedSourceDirs += xjcGenerate.outputDirectory
    }
}
  1. Затем сгенерируйте исходники:
./gradlew xjcGenerate

Ваши классы будут в каталоге src/main/generated-java с @XsdInfo аннотация. Для вашего случая наиболее интересен xsdElementPart его элемент.

  1. Во время выполнения вы можете просто запросить это и использовать по мере необходимости (класс Plugin содержит Configuration как внутренний класс):
    XsdInfo xsdAnnotation = plugin.getClass().getDeclaredAnnotation(XsdInfo.class);
    System.out.println(xsdAnnotation.xsdElementPart());

Я готовлю тест TestGeneratedMavenModel, чтобы полностью продемонстрировать это.

person Hubbitus    schedule 28.01.2019