使用JAXB提取XML元素的内部文本

Kar*_*rle 8 xml jaxb innertext

问题

给定以下XML配置文件:

<main>
  <name>JET</name>
  <maxInstances>5</maxInstances>
  <parameters>
    <a>1</a>
    <b>
      <b1>test1</b1>
      <b2>test2</b2>
    </b>
  </parameters>
</main>
Run Code Online (Sandbox Code Playgroud)

我需要提取name和maxInstances元素的值,然后提取参数元素的整个内部文本.例如

name = "JET"
maxInstances = 5
parameters = "<a>1</a><b><b1>test1</b1><b2>test2</b2></b>"
Run Code Online (Sandbox Code Playgroud)

最终,参数块可以包含任何格式良好的XML.

试图解决方案

以下代码适用于name和maxInstances,但不适用于参数:

@XmlRootElement(name="main")
public class Main {

    @XmlElement(name="name", required="true")
    private String name;

    @XmlElement(name="maxInstances", required="true")
    private Integer maxInstances;

    @XmlElement(name="parameters")
    private String parameters;

}
Run Code Online (Sandbox Code Playgroud)

我已经尝试过基于以下想法的解决方案,但找不到合适的东西.

我可以使用不同的类型来表示我可以解析以生成字符串的XML树的参数对象吗?例如

@XmlElement(name="parameters")
private XmlNodeObject parametersNode;

public String getParameters() {
    // Collapse node to single line of text
    return innerText;
}
Run Code Online (Sandbox Code Playgroud)

或者我需要使用一些不同类型的注释?

@XmlSpecialAnnotation(...)
@XmlElement(name="parameters")
private String parameters;
Run Code Online (Sandbox Code Playgroud)

我是否需要切换到不同风格的解析器?使用两种样式的解析器是好/坏的想法?

bdo*_*han 11

您可以使用@XmlAnyElement注释如bmargulies描述.要映射到问题中的对象模型,您可以利用a DOMHandler.

主要

import javax.xml.bind.annotation.*;

@XmlRootElement(name="main")
@XmlAccessorType(XmlAccessType.FIELD)
public class Main {

    private String name;

    private Integer maxInstances;

    @XmlAnyElement(value=ParameterHandler.class)
    private String parameters;

}
Run Code Online (Sandbox Code Playgroud)

ParameterHandler

import java.io.*;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.annotation.DomHandler;
import javax.xml.transform.Source;
import javax.xml.transform.stream.*;

public class ParameterHandler implements DomHandler<String, StreamResult> {

    private static final String PARAMETERS_START_TAG = "<parameters>";
    private static final String PARAMETERS_END_TAG = "</parameters>";
    private StringWriter xmlWriter = new StringWriter(); 

    public StreamResult createUnmarshaller(ValidationEventHandler errorHandler) {
        return new StreamResult(xmlWriter);
    }

    public String getElement(StreamResult rt) {
        String xml = rt.getWriter().toString();
        int beginIndex = xml.indexOf(PARAMETERS_START_TAG) + PARAMETERS_START_TAG.length();
        int endIndex = xml.indexOf(PARAMETERS_END_TAG);
        return xml.substring(beginIndex, endIndex);
    }

    public Source marshal(String n, ValidationEventHandler errorHandler) {
        try {
            String xml = PARAMETERS_START_TAG + n.trim() + PARAMETERS_END_TAG;
            StringReader xmlReader = new StringReader(xml);
            return new StreamSource(xmlReader);
        } catch(Exception e) {
            throw new RuntimeException(e);
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

演示

import java.io.File;
import javax.xml.bind.*;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Main main = (Main) unmarshaller.unmarshal(new File("input.xml"));

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(main, System.out);
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 启动代码时,我面临以下异常:[com.sun.istack.SAXException2:封送von Typ“ java.lang.String” als元素被保留,weine eine @ XmlRootElement-Annotation fehlt]。但这似乎是jaxb中的错误。 (2认同)

bma*_*ies 6

最接近的是通过声明变量将'参数'映射到DOM树org.w3c.dom.Node.(实际上,声明一个JAXBElement).

有关详细信息,请参阅http://jaxb.java.net/guide/Avoid_strong_databinding.html.这为您提供了架构优先处方,您可以通过xsd2java运行该架构并查看输出,了解如何从java启动.

要获取字符串,您必须从DOM序列化.

或者,更具体地说:

此页面描述了xsd:任何处理,因此

  @XmlAnyElement
  public List<Element> getParameters();
Run Code Online (Sandbox Code Playgroud)

ElementDOM接口在哪里.