How to ignore casing of element names in JaxB

后端 未结 3 1883
庸人自扰
庸人自扰 2021-01-06 07:48

As stated in the title I want to ignore casing of element names in a document.

static class XY433 {
    @XmlAttribute(name = \"C200\")
    String c200;
    @         


        
相关标签:
3条回答
  • 2021-01-06 08:15

    I am using moxy 2.7.1 version and it is working fine with UnmarshallerProperty as below.

    unmarshaller.setProperty(UnmarshallerProperties.UNMARSHALLING_CASE_INSENSITIVE, true);
    

    eclipselink documentation

    0 讨论(0)
  • 2021-01-06 08:19

    Encounter the similar problem. My solution is to add @XmlAdpater on the model entity, which refers to your own XMLAdapter, this would give a flexible customization on the marshall/unmarshall.

    0 讨论(0)
  • 2021-01-06 08:35

    You could map all your properties to lower case node names, and then wrap an XMLStreamReader to call toLowerCase() on all attribute/element names it returned. Then unmarshal from that XMLStreamReader.

    I have recently added an enhance request for EclipseLink JAXB (MOXy) for this issue, feel free to provide additional information:

    • https://bugs.eclipse.org/bugs/show_bug.cgi?id=331241

    Object Model

    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlRootElement;
    
    @XmlRootElement
    public class Customer {
    
        private int id;
        private String name;
        private Address address;
    
        @XmlAttribute
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Address getAddress() {
            return address;
        }
    
        public void setAddress(Address address) {
            this.address = address;
        }
    
    }
    
    
    public class Address {
    
        private String street;
    
        public String getStreet() {
            return street;
        }
    
        public void setStreet(String street) {
            this.street = street;
        }
    
    }
    

    Demo Code

    import java.io.FileInputStream;
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.Marshaller;
    import javax.xml.bind.Unmarshaller;
    import javax.xml.stream.XMLInputFactory;
    import javax.xml.stream.XMLStreamReader;
    import javax.xml.stream.util.StreamReaderDelegate;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            JAXBContext jc = JAXBContext.newInstance(Customer.class);
    
            XMLInputFactory xif = XMLInputFactory.newInstance();
            XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("input.xml"));
            xsr = new MyStreamReaderDelegate(xsr);
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            Customer customer = (Customer) unmarshaller.unmarshal(xsr);
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(customer, System.out);
        }
    
        private static class MyStreamReaderDelegate extends StreamReaderDelegate {
    
            public MyStreamReaderDelegate(XMLStreamReader xsr) {
                super(xsr);
            }
    
            @Override
            public String getAttributeLocalName(int index) {
                return super.getAttributeLocalName(index).toLowerCase();
            }
    
            @Override
            public String getLocalName() {
                return super.getLocalName().toLowerCase();
            }
    
        }
    
    }
    

    Will read these XML documents:

    <CUSTOMER ID="1">
        <NAME>Jane Doe</NAME>
        <ADDRESS>
            <STREET>123 A Street</STREET>
        </ADDRESS>
    </CUSTOMER>
    
    <CuSToMeR Id="1">
        <NaMe>Jane Doe</NAME>
        <AdDrEsS>
            <STREET>123 A Street</STREET>
        </AdDRrEsS>
    </CuSToMeR>
    

    And write the following XML:

    <customer id="1">
       <address>
          <street>123 A Street</street>
       </address>
       <name>Jane Doe</name>
    </customer>
    

    Below is a link to a more detailed example:

    • http://bdoughan.blogspot.com/2010/12/case-insensitive-unmarshalling.html

    UPDATE

    Your code works in my environment (JDK 1.6.0_20 with both the included JAXB, and EclipseLink JAXB (MOXy) 2.2, I'm also using the default implementation of StAX). When I run your example:

    import java.io.FileInputStream;
    import java.util.List;
    
    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.Unmarshaller;
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.stream.XMLInputFactory;
    import javax.xml.stream.XMLStreamReader;
    import javax.xml.stream.util.StreamReaderDelegate;
    
    public class Example {
    
        private static class ToLowerCaseNamesStreamReaderDelegate extends StreamReaderDelegate {
    
            public ToLowerCaseNamesStreamReaderDelegate(XMLStreamReader xsr) {
                super(xsr);
            }
    
            @Override
            public String getAttributeLocalName(int index) {
                return super.getAttributeLocalName(index).toLowerCase();
            }
    
            @Override
            public String getLocalName() {
                return super.getLocalName().toLowerCase();
            }
    
        }
    
    
        @XmlRootElement(name="doc")
        static class Doc {
            @XmlElement(name="element")
            List<Element> elements;
        }
    
        static class Element {
            @XmlAttribute(name = "abc")
            String abc;
        }
    
        public static void main(String[] args) throws Exception {
            XMLInputFactory xif = XMLInputFactory.newInstance();
            XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("LowerCaseElementNamesFilterTest.xml"));
    
            Unmarshaller u = JAXBContext.newInstance(Doc.class).createUnmarshaller();
    
            //Do unmarshalling
            Doc doc = (Doc) u.unmarshal(new ToLowerCaseNamesStreamReaderDelegate(xsr));
    
            System.out.println(doc.elements.get(0).abc);
            System.out.println(doc.elements.get(1).abc);
            System.out.println(doc.elements.get(2).abc);
    
        }
    }
    

    I get the following output:

    1
    1
    2
    

    UPDATE #2

    To address:

    Exception in thread "main" javax.xml.bind.UnmarshalException - with linked exception: [javax.xml.bind.UnmarshalException: Namespace URIs and local names to the unmarshaller needs to be interned.] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:425) at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:362) at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:332)

    Have you tried modifying the delegate?:

    @Override
    public String getAttributeLocalName(int index) {
        return super.getAttributeLocalName(index).toLowerCase().intern();
    }
    
    @Override
    public String getLocalName() {
        return super.getLocalName().toLowerCase().intern();
    }
    
    0 讨论(0)
提交回复
热议问题