开发者

binding xml value as either attribute or element

Spring framework's xml syntax is somewhat flexible. It allows you to define some information either as attribute or as a nested element. E.g.,

<property name="accountDao" ref="accountDao"/>

or

<property name="accountDao">
    <ref bean="accountDao">
</property>

I want to do something similar in my code

<a b="foo">开发者_运维百科

and

<a>
    <attr name="b">foo</attr>
</a>

The intention is to give the user the simplicity of using attributes, up to the point where the attribute name is too complex (e.g., has a space in it) or the value is multi-line. But there is a catch: I want to use some binding or serialization framework, like xstream or jaxb, instead of the usual stax or dom apis in which I have to manually go over the entire xml and create my objects.

So far I haven't figured out how to define such mappings with xstream or jaxb, from a Java field to two places in the xml.

I tried to use xjc (java 6 jvm) with Spring's xsd. I thought maybe I'll find some insights in the generated objects. However, xjc failed with some errors.

Any other ideas?


Note: I'm the EclipseLink JAXB (MOXy) lead, and a member of the JAXB 2.X (JSR-222) expert group.

You can leverage MOXy's XML metadata for this use case to apply multiple bindings to a field/property:

binding.xml

The metadata is supplied via MOXy's XML metadata format. This metadata supplements what is provided via JAXB and MOXy's annotations:

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="example">
    <java-types>
        <java-type name="A">
            <xml-root-element/>
            <java-attributes>
                <xml-attribute java-attribute="b"/>
                <xml-element java-attribute="b" xml-path="attr[@name='b']/text()" read-only="true"/>
            </java-attributes>
        </java-type>
    </java-types>
</xml-bindings>

Demo

The following code demonstrates how to bootstrap the MOXy implementation of JAXBContext with the mapping file.

package example;

import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.eclipse.persistence.jaxb.JAXBContextFactory;

public class Demo {

    private static final String ATTRIBUTE_XML = "<a b='foo'/>";
    private static final String ELEMENT_XML = "<a><attr name='b'>bar</attr></a>";

    public static void main(String[] args) throws Exception {
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "example/binding.xml");
        JAXBContext jc = JAXBContext.newInstance(new Class[] {A.class}, properties);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        A a1 = (A) unmarshaller.unmarshal(new StringReader(ATTRIBUTE_XML));
        marshaller.marshal(a1, System.out);

        A a2 = (A) unmarshaller.unmarshal(new StringReader(ELEMENT_XML));
        marshaller.marshal(a2, System.out);
    }

}

A

package example;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class A {

    private String b;

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

}

Output

Even though MOXy can unmarshal the different formats, the marshal format is the same.

<?xml version="1.0" encoding="UTF-8"?>
<a b="foo"/>
<?xml version="1.0" encoding="UTF-8"?>
<a b="bar"/>

For More Information

  • http://bdoughan.blogspot.com/2010/12/extending-jaxb-representing-annotations.html
  • http://bdoughan.blogspot.com/2011/03/map-to-element-based-on-attribute-value.html
  • http://bdoughan.blogspot.com/2011/05/specifying-eclipselink-moxy-as-your.html
  • http://wiki.eclipse.org/EclipseLink/Examples/MOXy/Spring
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜