Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Loading XML without given namespace as EMF Model: "Package with uri 'null' not found" - Exception

I have a XSD-File, which I transformed into an ecore-model and from where I generated model code. Now i would like to load a xml-file for that schema, but keep getting the error:

org.eclipse.emf.ecore.xmi.PackageNotFoundException: 
Package with uri 'null' not found.
(file:/C:/Users/mboeschen/safety/devel/eclipse_plugins...
/de.offis.etas.load/examples/minimal.xml, 2, 7)

As this is directly after the root tag in my xml file I suspect that something is going wrong after reading the root tag.

My code is the following:

public static void main(String[] args) throws IOException {

    MinimalPackage.eINSTANCE.eClass();  
    MinimalPackage packageInstance = MinimalPackage.eINSTANCE;
    Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE;
    Map<String, Object> m = reg.getExtensionToFactoryMap();
    m.put("*", new XMLResourceFactoryImpl());

    // Obtain a new resource set
    ResourceSet resSet = new ResourceSetImpl();
    resSet.setResourceFactoryRegistry(reg);

    resSet.getPackageRegistry().put(MinimalPackage.eNS_URI,
            MinimalPackage.eINSTANCE);
    resSet.getPackageRegistry().put(null,
            MinimalPackage.eINSTANCE);

    // Get the resource
    URI uri = URI
    .createFileURI("C:/Users/mboeschen/safety/devel/eclipse_plugins...
                    /de.offis.etas.load/examples/minimal.xml");
    Resource resource = resSet.getResource(uri, true);
    RootType r = (RootType) resource.getContents().get(0);

    System.out.println(r);

The schema file looks like this:

<?xml version="1.0" encoding="US-ASCII"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" >
<xs:element name="Root">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="Inner" type="MyType">
            </xs:element>
        </xs:sequence>
    </xs:complexType>
</xs:element>
<xs:complexType name="MyType">
    <xs:sequence> </xs:sequence>
</xs:complexType>
</xs:schema>

And this is the xml file:

<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Inner>
</Inner>
</Root>

Any ideas what is happening here? Any help appreciated!

like image 876
Martin Böschen Avatar asked Oct 14 '13 15:10

Martin Böschen


2 Answers

In the last two years, I have refined the solution proposed by @Severin for my project. Therefore, I give an additional answer as follows:

When a resource is loaded via the XMLResource, several helper classes are called to parse and map the XML to EMF/Ecore. Most of those classes can be replaced by changing the load options. There are several locations where this can be done:

  • the ResourceSet has default load options
  • the Resource default load options (which are typically set via the generated ResourceFactory)
  • the Resource.load() method can be provided with load options

Depending on the access you have (your own generated code vs. 3rd party generated code) and the location/frequency where the resource is loaded, you need to use one of those alternatives to add to the load options.

Load options come as a key-value map. The keys are defined by constants in Resource and XMLResource, for example.

Two keys are of special interest for the problem described initially:

  • XMLResource.OPTION_MISSING_PACKAGE_HANDLER provides a handler which is called if EMF cannot find a suitable EPackage
  • XMLResource.OPTION_EXTENDED_META_DATA yields either a boolean (indicating whether to use extended meta-data, usually true), or a concrete instance of ExtendedMetaData, which provides all kinds of mapping information between XML and Ecore.

For simple cases, when

  • there is just one namespace and one EPackage involved
  • the content type of the resource is unambiguous (i.e., you /know/ that the resource contains content matching you EPackage)

you can just give a MissingPackageHandler implementation like this one:

MissingPackageHandler mph = new MissingPackageHandler() {
  @Override
  public EPackage getPackage(final String nsURI) {
    return MyModelEPackage.eINSTANCE;
  }
};

And at least in my project, I also needed to set this ExtendedMetaData:

BasicExtendedMetaData bemd = new BasicExtendedMetaData(new EPackageRegistryImpl(EPackage.Registry.INSTANCE)) {
  @Override
  protected boolean isFeatureNamespaceMatchingLax() {
    return true;
  }
};

If more than one EPackages and namespaces are involved, then the MissingPackageHandler might be too high-level and the distinction needs to be done directly by the ExtendedMetaData implementation.

Following the answer of @Severin, this could be done like this:

BasicExtendedMetaData bemd = new BasicExtendedMetaData() {
  private static final String NAMESPACE_GOOGLE_EXT_2_2 = "http://www.google.com/kml/ext/2.2";
  private static final String NAMESPACE_OPENGIS_2_2 = "http://www.opengis.net/kml/2.2";
  private static final String NAMESPACE_DEFAULT = NAMESPACE_OPENGIS_2_2;

  @Override
  public EPackage getPackage(String namespace) {
    if(namespace==null) {
      namespace = NAMESPACE_DEFAULT;
    }
    return super.getPackage(namespace);
  }

  @Override
  public EStructuralFeature getElement(String namespace, String name) {
    // try to find feature in OPENGIS package
    EStructuralFeature result = super.getElement(NAMESPACE_OPENGIS_2_2, name);
    if (feature == null) {
      // if not found, try GOOGLE_EXT
      feature = super.getElement(NAMESPACE_GOOGLE_EXT_2_2, name);
    }
    return feature;
  }
});
like image 186
Stefan Winkler Avatar answered Sep 29 '22 09:09

Stefan Winkler


When you generated your model, you probably got a generated [YourModelName]ResourceFactoryImpl class. I have experienced the same problem for my KML editor, that is how I solved it:

    public class OgckmlResourceFactoryImpl extends ResourceFactoryImpl {
            ...
        /**
         * Creates an instance of the resource.
         * <!-- begin-user-doc -->
         * <!-- end-user-doc -->
         * @generated NOT
         */
        @Override
        public Resource createResource(URI uri) {
            XMLResource result = new OgckmlResourceImpl(uri);
            setupOptions(result);
            return result;
        }

        protected void setupOptions(XMLResource result)
        {
            ...
            result.getDefaultLoadOptions().put(XMLResource.OPTION_EXTENDED_META_DATA, new BasicExtendedMetaData()
            {
                private static final String NAMESPACE_GOOGLE_EXT_2_2 = "http://www.google.com/kml/ext/2.2";
                private static final String NAMESPACE_OPENGIS_2_2 = "http://www.opengis.net/kml/2.2";
                private static final String NAMESPACE_DEFAULT = NAMESPACE_OPENGIS_2_2;

                @Override
                public EPackage getPackage(String namespace) {
                    if(namespace==null){
                        namespace = NAMESPACE_DEFAULT;
                    }
                    return super.getPackage(namespace);
                }

                @Override
                public EStructuralFeature getElement(String namespace, String name)
                {
                    if (feature == null)
                        feature = super.getElement(NAMESPACE_OPENGIS_2_2, name);
                    if (feature == null)
                        feature = super.getElement(NAMESPACE_GOOGLE_EXT_2_2, name);
                    return feature;
                }
        });
...
    }
    }
like image 44
Severin Avatar answered Sep 29 '22 09:09

Severin