Dealing with poorly designed XML with JAXB

后端 未结 4 965
野的像风
野的像风 2021-01-13 05:21

I\'m currently working on replacing a legacy system with JAXB and I\'m running into problem with parsing the XML. The number one requirement of the system is that it must be

相关标签:
4条回答
  • 2021-01-13 05:42

    If you want to handle at the s# items as a collection:

    import java.io.Serializable;
    import java.util.List;
    
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;
    
    @XmlRootElement(name="xx")
    public class XMLXx implements Serializable {
    
        private static final long serialVersionUID = 4064597372833234503L;
    
        private List<XMLSite> sites;
    
        @XmlElement(name="s")
        public List<XMLSite> getSites() {
            return sites;
        }
    
        public void setSites(List<XMLSite> sites) {
            this.sites = sites;
        }
    
    }
    

    Then you could do something like to fool JAXB into thinking all the elements (s1, s2, etc) are actually called s:

    import java.io.FileInputStream;
    
    import javax.xml.bind.JAXBContext;
    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(XMLXx.class);
    
            XMLInputFactory xif = XMLInputFactory.newInstance();
            XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("input.xml"));
            xsr = new SiteStreamReaderDelegate(xsr);
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            XMLXx object = (XMLXx) unmarshaller.unmarshal(xsr);
            System.out.println(object.getSites().size());
    
        }
    
        private static class SiteStreamReaderDelegate extends StreamReaderDelegate {
    
            public SiteStreamReaderDelegate(XMLStreamReader xsr) {
                super(xsr);
            }
    
            @Override
            public String getLocalName() {
                String localName = super.getLocalName();
                if(localName.startsWith("s")) {
                    return "s";
                }
                return localName;
            }
    
        }
    }
    

    For a similar example see:

    • http://bdoughan.blogspot.com/2010/12/case-insensitive-unmarshalling.html
    0 讨论(0)
  • 2021-01-13 05:44

    JaxB does not support "dynamic" tags. Since can only be 256 of these, use a script to generate source.

    0 讨论(0)
  • 2021-01-13 05:51

    Write a meta-XSD in freemarker/velocity or the like. It can define the 256 types as subtypes of some parent type using a for loop. If you want to fully automate, you can write a maven plugin to generate the XSD from the freemarker and the run generate-sources on the result.

    0 讨论(0)
  • 2021-01-13 06:01

    No, I don't think so, not with standard JAXB. You could, in principle use @XmlMixed, but you'd still end up with a bunch of DOM Element objects, not bound classes. Some proprietary JAXB extension such as MOXy might be able to handle it, though.

    This isn't really a good use case for JAXB. As you say, the XML is poorly designed. You'd be better off parsing this by hand (using e.g. STAX or DOM), and building the desired object model yourself.

    0 讨论(0)
提交回复
热议问题