reordering XML tags

此生再无相见时 提交于 2020-01-04 01:50:55

问题


I am trying to implement something which is for writing back the content tree of java object to XML file (object marshalling) (I know there are a lot of APIs for doing that but its required from me), I want to let the user to reorder the tags as he/she wants, I know using annotation like what JAXB has may solve that, but I think using annotation may cause a lot of pain. it will be so helpful if any one could offer any good approach.

Thanks


回答1:


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

In another answer I described the standard JAXB mechanisms for specifying the order of elements. In this answer I will explain how MOXy's external mapping document can be used to address this part of your question:

I want to let the user to reorder the tags as he/she wants, I know using annotation like what JAXB has may solve that, but I think using annotation may cause a lot of pain.

Root

In the Root class I have used the @XmlType annotation to specify an ordering.

package forum11217734;

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlType(propOrder={"c", "b", "a"})
public class Root {

    private String a;
    private String b;
    private String c;

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

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

    public String getC() {
        return c;
    }

    public void setC(String c) {
        this.c = c;
    }

}

jaxb.properties

To specify MOXy as your JAXB provider you need to add a file called jaxb.properties in the same package as your domain model with the following entry (see Specifying EclipseLink MOXy as Your JAXB Provider):

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

binding-acb.xml

MOXy has an external mapping document extension that allows you to override the mappings on the domain model (see Extending JAXB - Representing Metadata as XML). We will use this document to specify another ordering.

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum11217734">
    <java-types>
        <java-type name="Root">
            <xml-type prop-order="a c b"/>
        </java-type>
    </java-types>
</xml-bindings>

binding-cab.xml

We can use additional mapping documents to provide alternate orderings.

<?xml version="1.0"?>
<xml-bindings
    xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
    package-name="forum11217734">
    <java-types>
        <java-type name="Root">
            <xml-type prop-order="c a b"/>
        </java-type>
    </java-types>
</xml-bindings>

Demo

The following demo code demonstrates how to leverage the external mapping document when creating a JAXBContext. We will marshal the same instance of Root three different ways.

package forum11217734;

import java.util.*;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.JAXBContextFactory;

public class Demo {

    public static void main(String[] args) throws Exception {
        Root root = new Root();
        root.setA("Foo");
        root.setB("Bar");
        root.setC("Baz");

        // CBA
        JAXBContext cbaContext = JAXBContext.newInstance(Root.class);
        Marshaller cbaMarshaller = cbaContext.createMarshaller();
        cbaMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        cbaMarshaller.marshal(root, System.out);

        // ACB
        Map<String, Object> acbProperties = new HashMap<String, Object>(1);
        acbProperties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum11217734/binding-acb.xml");
        JAXBContext acbContext = JAXBContext.newInstance(new Class[] {Root.class}, acbProperties);
        Marshaller acbMarshaller = acbContext.createMarshaller();
        acbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        acbMarshaller.marshal(root, System.out);

        // CAB
        Map<String, Object> cabProperties = new HashMap<String, Object>(1);
        cabProperties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum11217734/binding-cab.xml");
        JAXBContext cabContext = JAXBContext.newInstance(new Class[] {Root.class}, cabProperties);
        Marshaller cabMarshaller = cabContext.createMarshaller();
        cabMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        cabMarshaller.marshal(root, System.out);
    }

}

Output

Below is the output from running the demo code:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <c>Baz</c>
   <b>Bar</b>
   <a>Foo</a>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
   <a>Foo</a>
   <c>Baz</c>
   <b>Bar</b>
</root>
<?xml version="1.0" encoding="UTF-8"?>
<root>
   <c>Baz</c>
   <a>Foo</a>
   <b>Bar</b>
</root>



回答2:


JAXB (JSR-222) implementations provide a couple different mechanisms for specifying the order of XML elements when then content is marshalled to XML. JAXB does not require the elements be in order when unmarshalling.

OPTION #1 - @XmlType(propOrder={"c","b", "a"})

The propOrder property on the @XmlType annotation allows you to specify an order.

Root

package forum11217734;

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlType(propOrder={"c","b", "a"})
public class Root {

    private String a;
    private String b;
    private String c;

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

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

    public String getC() {
        return c;
    }

    public void setC(String c) {
        this.c = c;
    }

}

Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <c>Baz</c>
    <b>Bar</b>
    <a>Foo</a>
</root>

For More Information

  • http://blog.bdoughan.com/2012/02/jaxbs-xmltype-and-proporder.html

OPTION #2 - @XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)

You can also use the @XmlAccessorOrder annotation to specify that the properties should be marshalled in alphabetical order.

Root

package forum11217734;

import javax.xml.bind.annotation.*;

@XmlRootElement
@XmlAccessorOrder(XmlAccessOrder.ALPHABETICAL)
public class Root {

    private String a;
    private String b;
    private String c;

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

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

    public String getC() {
        return c;
    }

    public void setC(String c) {
        this.c = c;
    }

}

Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
    <a>Foo</a>
    <b>Bar</b>
    <c>Baz</c>
</root>

DEMO CODE

The following demo code was used to produce the output for each of the options above.

package forum11217734;

import javax.xml.bind.*;

public class Demo {

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

        Root root = new Root();
        root.setA("Foo");
        root.setB("Bar");
        root.setC("Baz");

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

}


来源:https://stackoverflow.com/questions/11217734/reordering-xml-tags

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!