JAXB unmarshalling of “generic” real world documents

后端 未结 2 1248
死守一世寂寞
死守一世寂寞 2021-01-23 06:37

We have a large set of configuration documents of the style


  
    ...more content
  
  

        
相关标签:
2条回答
  • 2021-01-23 07:23

    You could do something like the following with JAXB (JSR-222) and StAX (JSR-173):

    Demo

    A StAX XMLStreamReader can be used to parse the XML document. You can use it to advance to a bar element, then you can read the class attribute and load the appropriate Java class from a ClassLoader. Then you can leverage one of the unmarshal methods that takes a class parameter.

    package forum12402215;
    
    import javax.xml.bind.*;
    import javax.xml.stream.*;
    import javax.xml.transform.stream.StreamSource;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            ClassLoader classLoader = Bork.class.getClassLoader();
            JAXBContext jc = JAXBContext.newInstance(Bork.class, Gnarf.class);
            Unmarshaller unmarshaller = jc.createUnmarshaller();
    
            StreamSource source = new StreamSource("src/forum12402215/input.xml");
            XMLInputFactory xif = XMLInputFactory.newFactory();
            XMLStreamReader xsr = xif.createXMLStreamReader(source);
            xsr.nextTag(); // Advance to "foo" element
            xsr.nextTag(); // Advance to "bar" element
    
            while(xsr.getLocalName().equals("bar")) {
                 String className = xsr.getAttributeValue("", "class");
                 Class<?> clazz = classLoader.loadClass(className);
                 Object object = unmarshaller.unmarshal(xsr, clazz).getValue();
                 System.out.println(object);
                 xsr.nextTag();
            }
        }
    
    }
    

    Bork

    Below is a sample Bork class.

    package forum12402215;
    
    public class Bork {
    
        private String b;
    
        public String getB() {
            return b;
        }
    
        public void setB(String b) {
            this.b = b;
        }
    
        @Override
        public String toString() {
            return "Bork(b=" + b + ")";
        }
    
    }
    

    Gnarf

    Below is a sample Gnarf class:

    package forum12402215;
    
    public class Gnarf {
    
        private int a;
    
        public int getA() {
            return a;
        }
    
        public void setA(int a) {
            this.a = a;
        }
    
        @Override
        public String toString() {
            return "Gnarf(a=" + a + ")";
        }
    
    }
    

    input.xml

    Below is he sample document I used used for this example based on the one from your question. I changed the package names.

    <?xml version="1.0" encoding="UTF-8"?>
    <foo>
        <bar class="forum12402215.Gnarf">
            <a>123</a>
        </bar>
        <bar class="forum12402215.Bork">
            <b>Hello World</b>
        </bar>
    </foo>
    

    Output

    Below is the output from running the demo code.

    Gnarf(a=123)
    Bork(b=Hello World)
    
    0 讨论(0)
  • 2021-01-23 07:30

    If the structure really is that simple I'd be tempted to parse the top two levels (foo and the class attribute of bar) myself using an XMLStreamReader, then hand the reader off to the JAXB unmarshaller to parse each bar, assembling the results into a list. I wouldn't bother trying to parse the outer envelope layers using JAXB directly.

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