Unmarshaller and schema in JAXB

烈酒焚心 提交于 2020-01-13 11:08:09

问题


I have application that can save file in various formats (all of them is xml). So I should solve problem with determination in what format file have been saved. So, I see 2 solutions

  • different formats have different schemas, so I could determine it by them. I set schemas in way that I get from here

marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "bla-bla.xsd");

so I suppose I can get it using unmarshaller.getProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION)

but it throwing

javax.xml.bind.PropertyException: jaxb.noNamespaceSchemaLocation

and getSchema() return null So, how can I get schema location?

  • Specifying different adapters for different beans using setAdapter(Class<A> type, A adapter) method

What way is preferable? If first, then how can I get schema location label?

upd code example suppose we have bean

@XmlRootElement
public class Foo{
    String bar;
    public String getBar() {return bar; }
    public void setBar(String bar) {this.bar = bar;}
}

and code that generates schema, saves Foo's instances and loads then.

public class Test {
    final static String schemaLoc = "fooschema.xsd";


    public static void write(File file, Foo foo, Schema schema) throws Throwable {
        XMLEventWriter xsw = null;
        try{
            JAXBContext context = JAXBContext.newInstance(Foo.class);
            XMLOutputFactory xof = XMLOutputFactory.newInstance();
            OutputStream out = new FileOutputStream(file);
            xsw = xof.createXMLEventWriter(out);
            Marshaller m = context.createMarshaller();
            m.setSchema(schema);    //schema setted
            System.out.println(">>>marchal : " + m.getSchema());    //check it
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
            m.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, schemaLoc);
            m.marshal(foo, xsw);
        } finally{
             xsw.close();
        }
    }

    public static Foo load(File file) throws Throwable {
        JAXBContext context = JAXBContext.newInstance(Foo.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();


        System.out.println("unmarshaller schema:" + unmarshaller.getSchema());  //I need get it here
    //  System.out.println("schema_prop:" + unmarshaller.getProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION));

        InputStreamReader in = new InputStreamReader(new FileInputStream(file));
        XMLEventReader xer = XMLInputFactory.newInstance()
                .createXMLEventReader(in);
        return Foo.class.cast(unmarshaller.unmarshal(xer));
    }

    private static File createSchema(String schemaLocation) throws Throwable{
        final File target = new File(schemaLocation);
        if(!target.exists()){
            JAXBContext jaxbContext = JAXBContext.newInstance(Foo.class);
            SchemaOutputResolver sor = new SchemaOutputResolver() {
                public Result createOutput(String namespaceURI, String suggestedFileName)
                throws IOException {
                    StreamResult result = new StreamResult(target);
                    result.setSystemId(target.toURI().toURL().toString());
                    return result;
                }
            };
            jaxbContext.generateSchema(sor);
        }
        return target;
    }

    public static void main(String[] args) throws Throwable {
        createSchema(schemaLoc);
        File file = new File("temp.xml");
        Foo foo = new Foo();
        foo.setBar("test bar");
        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        Schema schema = factory.newSchema(createSchema(schemaLoc));
        write(file, foo, schema);
        System.out.println("result " + load(file).getBar());
    }

}

schema that generates

      <xs:element name="foo" type="foo"/>

      <xs:complexType name="foo">
        <xs:sequence>
          <xs:element name="bar" type="xs:string" minOccurs="0"/>
        </xs:sequence>
      </xs:complexType>
    </xs:schema>

our temp file

<?xml version="1.0"?>
<foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="fooschema.xsd">
<bar>test bar</bar></foo>

as we see, there is

xsi:noNamespaceSchemaLocation="fooschema.xsd"

How I can get this text using JAXB?


回答1:


I would leverage a StAX parser to get this information (see example below). Create an XMLStreamReader on the input. Advance the XMLStreamReader to the root element using the nextTag() method. Then grab the noNamespaceSchemaLocation attribute of the root element. Then pass the XMLStreamReader to the unmarshal(XMLStreamReader) method on Unmarshaller.

import java.io.FileInputStream;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamReader;

public class Demo {

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

        XMLInputFactory xif = XMLInputFactory.newInstance();
        FileInputStream fis = new FileInputStream("input.xml");
        XMLStreamReader xsr = xif.createXMLStreamReader(fis);
        xsr.nextTag();
        String noNamespaceSchemaLocation = xsr.getAttributeValue(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "noNamespaceSchemaLocation");
        System.out.println(noNamespaceSchemaLocation);

        Unmarshaller um = context.createUnmarshaller();
        Categories response = (Categories) um.unmarshal(xsr);
    }
}



回答2:


You have to provide it with the location of your schema by using a file our fileoutputstream reference:

http://download.oracle.com/javase/6/docs/api/javax/xml/bind/Marshaller.html

EDIT:

Sorry, after reading further, you actually want the location of the schema, not the XML file, and there are quite a few examples online. Most of them like this one:

http://robaustin.wikidot.com/how-to-improve-perforamance-of-jaxb

Show how to pass in the schema location using a context class loader.

EDIT:

Per your comments:

http://download.oracle.com/javase/6/docs/api/javax/xml/bind/Marshaller.html#getSchema%28%29

getSchema() will return null if there is no schema set on the marshaller. That is why you can't get the property you want because it (the schema) doesn't exist.



来源:https://stackoverflow.com/questions/4478666/unmarshaller-and-schema-in-jaxb

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