5

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!

Justin
  • 24,288
  • 12
  • 92
  • 142
Martin Böschen
  • 1,707
  • 15
  • 22

3 Answers3

4

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;
  }
});
Stefan Winkler
  • 3,871
  • 1
  • 18
  • 35
2

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;
                }
        });
...
    }
    }
Severin
  • 296
  • 2
  • 8
  • This solution works (almost...). I also had to override `BasicExtendedMetadata#getElement(EClass, String, String)` and in the code given here, there is an omission in `getElement`, because the `feature` variable is not declared. Also, if the options should only be used once, they can be passed to `resource.load()` from the client code. Then the generated code does not have to be modified. – Stefan Winkler Apr 01 '15 at 19:29
  • @StefanWinkler could you please elaborate? What did you have to do to overrride `BasicExtendedMetadata#getElement(EClass, String, String)`? What do you mean by passed to `resource.load()` from the client code? And would any of these fix an editor for 3rd-party-generated XML with no `xmlns` attribute at the root? – tony_tiger Aug 01 '17 at 06:39
  • 1
    @tony_tiger I have created a more verbose answer now, because I noticed that the original answer is 2 years old and I have fine-tuned the options for my case. If both the generated code and the loading code is 3rd party and you cannot modify either, the only thing I could think of would be trying to subclass the generated 3rd party resource factory, add the options there, and then try to register your subclass in the global EMF Resource.Factory.Registry. But you need to take care of timing, because you want to override the existing factory, not be overridden yourself ... – Stefan Winkler Aug 01 '17 at 15:21
0

I have the same problem on ATL perspective, What I did to avoid problem of "PackageNotFoundException" : Fist You shouldn't let ur model namespace NULL, Identify namespace of URI “nsURI” would help to identify Ecore model in code generators “xml files . So just naming nsURI , any name would matches of ur EPackage. Also I rewrite xsi:schemeLocation="...." manulay,maybe this isn't make sense but at the end it's solve the prob

elay221
  • 61
  • 8