Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用Jaxb将部分XML解组到org.jdom.Element的实例_Java_Xml_Jaxb_Moxy - Fatal编程技术网

Java 使用Jaxb将部分XML解组到org.jdom.Element的实例

Java 使用Jaxb将部分XML解组到org.jdom.Element的实例,java,xml,jaxb,moxy,Java,Xml,Jaxb,Moxy,我在一个传统产品中工作,该产品严重依赖于org.jdom项目()的版本1和手动构造的XMLs,但我希望尽可能多地使用Jaxb。我们使用Moxy作为Jaxb实现 假设我有以下xml: <foo bar="bar"> <baz> <test value="something" /> </baz> </foo> 由于遗留代码将baz元素用作org.jdom.element,我希望Jaxb将内部元素“baz

我在一个传统产品中工作,该产品严重依赖于org.jdom项目()的版本1和手动构造的XMLs,但我希望尽可能多地使用Jaxb。我们使用Moxy作为Jaxb实现

假设我有以下xml:

<foo bar="bar">
    <baz>
        <test value="something" />
    </baz>
</foo>

由于遗留代码将baz元素用作org.jdom.element,我希望Jaxb将内部元素“baz”解组为org.jdom.element,但解组中的v始终是空字符串(“”),因此baz变为null。 我在下面创建了一个示例,其中我尝试使用XmlAdapter,但无法使其工作

import java.io.ByteArrayInputStream;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.transform.stream.StreamSource;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.XMLOutputter;

public class Test {

  public static void main(String[] args) throws JAXBException {

    String fooString = "<foo bar=\"bar\"><baz><test value=\"something\" /></baz></foo>";
    JAXBContext jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory
            .createContext(new Class<?>[] {Foo.class}, null);
    javax.xml.bind.Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    Foo foo = unmarshaller
            .unmarshal(new StreamSource(new ByteArrayInputStream(fooString.getBytes(StandardCharsets.UTF_8))), Foo.class)
            .getValue();

    System.out.println(foo);
  }

  @XmlRootElement
  private static final class Foo {

    @XmlAttribute
    public String bar;

    @XmlElement
    @XmlJavaTypeAdapter(ElementAdapter.class)
    public Element baz;

    @Override
    public String toString() {
        return "Foo [bar=" + bar + ", baz=" + baz + "]";
    }

  }

  private static final class ElementAdapter extends XmlAdapter<String, Element> {

    @Override
    public Element unmarshal(String v) throws Exception {
        Document document = new SAXBuilder().build(new StringReader(v));
        return document.getRootElement();
    }

    @Override
    public String marshal(Element v) throws Exception {
        return new XMLOutputter(org.jdom.output.Format.getPrettyFormat()).outputString(v);
    }

  }

}
import java.io.ByteArrayInputStream;
导入java.io.StringReader;
导入java.nio.charset.StandardCharset;
导入javax.xml.bind.JAXBContext;
导入javax.xml.bind.JAXBException;
导入javax.xml.bind.annotation.XmlAttribute;
导入javax.xml.bind.annotation.xmlement;
导入javax.xml.bind.annotation.XmlRootElement;
导入javax.xml.bind.annotation.adapters.XmlAdapter;
导入javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
导入javax.xml.transform.stream.StreamSource;
导入org.jdom.Document;
导入org.jdom.Element;
导入org.jdom.input.SAXBuilder;
导入org.jdom.output.XMLOutputter;
公开课考试{
公共静态void main(字符串[]args)抛出JAXBEException{
字符串fooString=“”;
JAXBContext JAXBContext=org.eclipse.persistence.jaxb.JAXBContextFactory
.createContext(新类[]{Foo.Class},null);
javax.xml.bind.Unmarshaller Unmarshaller=jaxbContext.createUnmarshaller();
Foo-Foo=unmarshaller
.unmarshal(新的StreamSource(新的ByteArrayInputStream(fooString.getBytes(StandardCharsets.UTF_8))),Foo.class)
.getValue();
系统输出打印项次(foo);
}
@XmlRootElement
私有静态最终类Foo{
@XmlAttribute
公共字符串栏;
@XmlElement
@XmlJavaTypeAdapter(ElementAdapter.class)
公共元素baz;
@凌驾
公共字符串toString(){
返回“Foo[bar=“+bar+”,baz=“+baz+””;
}
}
私有静态最终类ElementAdapter扩展了XmlAdapter{
@凌驾
公共元素解组(字符串v)引发异常{
Document Document=new SAXBuilder().build(new StringReader(v));
return document.getRootElement();
}
@凌驾
公共字符串封送处理(元素v)引发异常{
返回新的XMLOutputer(org.jdom.output.Format.getPrettyFormat()).outputString(v);
}
}
}

也许我从错误的角度来攻击它。关于如何实现这一点有什么建议吗?

在解组时调试问题的一个好方法是使用
javax.xml.bind.helpers.DefaultValidationEventHandler

在您的情况下,您可以简单地将其添加到main方法中的解组器中,例如

// ...
javax.xml.bind.Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler());
// ...
当您在附加了验证处理程序的情况下按原样运行测试程序时,您将看到如下内容,这基本上告诉您没有与XML中的
test
元素对应的Java类

[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.6.1.v20150916-55dc7c3): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 47; unexpected element (uri:"", local:"test"). Expected elements are (none)]
我认为您假设您的
ElementAdapter
实现将读取并使用
baz
节点和所有子节点作为字符串。实际上,我认为(分页?)发生的事情是JAXB正在对XML树进行一些预遍历,在此期间,它看到您没有用于
test
的模型,并随后丢弃
test
及其属性


要了解这里的情况,首先简化模型,不要担心JDOM元素转换。请注意,我已经更改了顶级类的名称,这样它就不会与
Test
模型类冲突:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;

public class Main {

    public static void main(String[] args) throws JAXBException {
        String fooString = "<foo bar=\"bar\"><baz><test value=\"something\" /></baz></foo>";
        JAXBContext jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory
                .createContext(new Class<?>[] {Foo.class}, null);
        javax.xml.bind.Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler());
        Foo foo = unmarshaller
                .unmarshal(new StreamSource(new ByteArrayInputStream(fooString.getBytes(StandardCharsets.UTF_8))), Foo.class)
                .getValue();

        System.out.println(foo);
    }

    @XmlRootElement()
    public static class Foo {

        @XmlAttribute
        public String bar;

        @XmlElement
        public Baz baz;

        @Override
        public String toString() {
            return "<foo bar=\"" + bar + "\">" + baz.toString() + "</foo>";
        }
    }

    @XmlRootElement
    public static class Baz {

        @XmlElement
        public Test test;

        @Override
        public String toString() {
            return "<baz>" + test.toString() + "</baz>";
        }
    }

    @XmlRootElement
    public static class Test {
        @XmlAttribute
        public String value;

        @Override
        public String toString() {
            return "<test value=\"" + value + "\"/>";
        }
    }

}

虽然在转换为JDOM之前,您可能需要清理适配器中的
Baz
元素(去掉XML前导码等),但这应该或多或少满足您的需要。请注意,在
ElementAdapter
中实例化另一个
JAXBContext
可能是一个糟糕的想法,而且可能有一种更有效的方法可以将JAXB元素转换为JDOM元素。这段代码很容易在调试器中单步执行,这样您就可以看到发生了什么。

在解组时调试问题的好方法是使用
javax.xml.bind.helpers.DefaultValidationEventHandler

在您的情况下,您可以简单地将其添加到main方法中的解组器中,例如

// ...
javax.xml.bind.Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler());
// ...
当您在附加了验证处理程序的情况下按原样运行测试程序时,您将看到如下内容,这基本上告诉您没有与XML中的
test
元素对应的Java类

[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.6.1.v20150916-55dc7c3): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: org.xml.sax.SAXParseException; lineNumber: 1; columnNumber: 47; unexpected element (uri:"", local:"test"). Expected elements are (none)]
我认为您假设您的
ElementAdapter
实现将读取并使用
baz
节点和所有子节点作为字符串。实际上,我认为(分页?)发生的事情是JAXB正在对XML树进行一些预遍历,在此期间,它看到您没有用于
test
的模型,并随后丢弃
test
及其属性


要了解这里的情况,首先简化模型,不要担心JDOM元素转换。请注意,我已经更改了顶级类的名称,这样它就不会与
Test
模型类冲突:

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;

public class Main {

    public static void main(String[] args) throws JAXBException {
        String fooString = "<foo bar=\"bar\"><baz><test value=\"something\" /></baz></foo>";
        JAXBContext jaxbContext = org.eclipse.persistence.jaxb.JAXBContextFactory
                .createContext(new Class<?>[] {Foo.class}, null);
        javax.xml.bind.Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        unmarshaller.setEventHandler(new javax.xml.bind.helpers.DefaultValidationEventHandler());
        Foo foo = unmarshaller
                .unmarshal(new StreamSource(new ByteArrayInputStream(fooString.getBytes(StandardCharsets.UTF_8))), Foo.class)
                .getValue();

        System.out.println(foo);
    }

    @XmlRootElement()
    public static class Foo {

        @XmlAttribute
        public String bar;

        @XmlElement
        public Baz baz;

        @Override
        public String toString() {
            return "<foo bar=\"" + bar + "\">" + baz.toString() + "</foo>";
        }
    }

    @XmlRootElement
    public static class Baz {

        @XmlElement
        public Test test;

        @Override
        public String toString() {
            return "<baz>" + test.toString() + "</baz>";
        }
    }

    @XmlRootElement
    public static class Test {
        @XmlAttribute
        public String value;

        @Override
        public String toString() {
            return "<test value=\"" + value + "\"/>";
        }
    }

}

虽然在转换为JDOM之前,您可能需要清理适配器中的
Baz
元素(去掉XML前导码等),但这应该或多或少满足您的需要。请注意,在
ElementAdapter
中实例化另一个
JAXBContext
可能是一个糟糕的想法,而且可能有一种更有效的方法可以将JAXB元素转换为JDOM元素。这段代码很容易在调试器中单步执行,这样您就可以看到发生了什么。

我想我会分享一个适合我的解决方案

受到这篇文章的启发,文章提到Jaxb lea