【问题标题】:Using JAXB to extract inner text of XML element使用 JAXB 提取 XML 元素的内部文本
【发布时间】:2011-07-29 02:07:09
【问题描述】:

问题

给定以下 XML 配置文件:

<main>
  <name>JET</name>
  <maxInstances>5</maxInstances>
  <parameters>
    <a>1</a>
    <b>
      <b1>test1</b1>
      <b2>test2</b2>
    </b>
  </parameters>
</main>

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

name = "JET"
maxInstances = 5
parameters = "<a>1</a><b><b1>test1</b1><b2>test2</b2></b>"

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

尝试的解决方案

以下代码适用于名称和 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;

}

我尝试根据以下想法寻找解决方案,但找不到合适的解决方案。

是否有不同的类型可以用于表示 XML 树的参数对象,我可以解析以生成字符串?例如

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

public String getParameters() {
    // Collapse node to single line of text
    return innerText;
}

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

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

我需要切换到不同风格的解析器吗?使用两种风格的解析器是好还是坏?

【问题讨论】:

    标签: xml jaxb innertext


    【解决方案1】:

    您可以使用@XmlAnyElement 注解as described by bmargulies。要映射到您问题中的对象模型,您可以利用 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;
    
    }
    

    参数处理程序

    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);
            }
        }
    
    }
    

    演示

    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);
        }
    
    }
    

    【讨论】:

    • 嗨 Blaise,我想出了一些非常相似的东西,但你的例子绝对是对我所拥有的东西的改进。感谢您的详细回答。
    • 我在启动代码时遇到以下异常:[com.sun.istack.SAXException2: Marshalling von Typ "java.lang.String" als Element ist nicht möglich, weil eine @XmlRootElement-Annotation感觉]。但这似乎是 jaxb 中的一个错误。
    • 在 xsd 中有没有办法定义 @XmlAnyElement(value=ParameterHandler.class) ?
    • 如果上面的xml文件中的是一个集合,稍微修改一下DomHandler就可以解决问题stackoverflow.com/questions/23550197/…
    【解决方案2】:

    最接近的方法是将“参数”映射到 DOM 树,方法是将变量声明为 org.w3c.dom.Node。 (其实就是声明一个JAXBElement)。

    详情请见http://jaxb.java.net/guide/Avoid_strong_databinding.html。这为您提供了架构优先的处方,您可以通过 xsd2java 运行该架构并查看输出来了解如何从 java 开始。

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

    或者,更具体地说:

    this page here describes xsd:any processing, and thus

      @XmlAnyElement
      public List<Element> getParameters();
    

    Element 是 DOM 接口。

    【讨论】:

    • 非常感谢 bmargulies,不幸的是,我没有足够的声誉来支持您的回答。
    • 查看如何利用 @XmlAnyElement 的 DOMHandler 方面来处理非 DOM 属性:stackoverflow.com/questions/5537416/…
    猜你喜欢
    • 1970-01-01
    • 2011-10-13
    • 2020-06-29
    • 1970-01-01
    • 2020-12-15
    • 2013-10-06
    • 1970-01-01
    • 1970-01-01
    • 2020-06-30
    相关资源
    最近更新 更多