Загрузка XML без заданного пространства имен как модель EMF: "Пакет с URI 'null' не найден" - исключение
У меня есть XSD-файл, который я преобразовал в ecore-модель и откуда я сгенерировал код модели. Теперь я хотел бы загрузить xml-файл для этой схемы, но продолжаю получать ошибку:
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)
Поскольку это происходит непосредственно после корневого тега в моем XML-файле, я подозреваю, что что-то идет не так после чтения корневого тега.
Мой код следующий:
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);
Файл схемы выглядит так:
<?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>
И это XML-файл:
<?xml version="1.0" encoding="UTF-8"?>
<Root>
<Inner>
</Inner>
</Root>
Есть идеи, что здесь происходит? Любая помощь приветствуется!
3 ответа
За последние два года я усовершенствовал решение, предложенное @Severin для моего проекта. Поэтому я даю дополнительный ответ следующим образом:
Когда ресурс загружается через XMLResource
вызывается несколько вспомогательных классов для анализа и сопоставления XML с EMF/Ecore. Большинство этих классов можно заменить, изменив параметры загрузки. Есть несколько мест, где это можно сделать:
ResourceSet
имеет параметры загрузки по умолчаниюResource
параметры загрузки по умолчанию (которые обычно устанавливаются через сгенерированныйResourceFactory
)Resource.load()
метод может быть снабжен опциями загрузки
В зависимости от вашего доступа (ваш собственный сгенерированный код или сгенерированный сторонним кодом) и местоположения / частоты загрузки ресурса, вам нужно использовать одну из этих альтернатив, чтобы добавить к опциям загрузки.
Параметры загрузки представлены в виде карты ключ-значение. Ключи определяются константами в Resource
а также XMLResource
, например.
Два ключа представляют особый интерес для описанной проблемы:
XMLResource.OPTION_MISSING_PACKAGE_HANDLER
предоставляет обработчик, который вызывается, если EMF не может найти подходящий EPackageXMLResource.OPTION_EXTENDED_META_DATA
выдает либо логическое значение (указывающее, использовать ли расширенные метаданные, обычноtrue
) или конкретный случайExtendedMetaData
, который предоставляет все виды информации о сопоставлении между XML и Ecore.
Для простых случаев, когда
- задействовано только одно пространство имен и один пакет EPackage
- тип контента ресурса однозначен (т. е. вы / знаете / что ресурс содержит контент, соответствующий вашему EPackage)
Вы можете просто дать MissingPackageHandler
реализация, как этот:
MissingPackageHandler mph = new MissingPackageHandler() {
@Override
public EPackage getPackage(final String nsURI) {
return MyModelEPackage.eINSTANCE;
}
};
И по крайней мере в моем проекте мне также нужно было установить это ExtendedMetaData
:
BasicExtendedMetaData bemd = new BasicExtendedMetaData(new EPackageRegistryImpl(EPackage.Registry.INSTANCE)) {
@Override
protected boolean isFeatureNamespaceMatchingLax() {
return true;
}
};
Если более одного EPackage
s и пространства имен, то MissingPackageHandler
может быть слишком высокого уровня, и различие должно быть сделано непосредственно ExtendedMetaData
реализация.
Следуя ответу @Severin, это можно сделать так:
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;
}
});
Когда вы сгенерировали свою модель, вы, вероятно, получили сгенерированный класс [YourModelName]ResourceFactoryImpl. Я столкнулся с той же проблемой для моего редактора KML, вот как я решил ее:
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;
}
});
...
}
}
У меня та же проблема с точки зрения ATL, что я сделал, чтобы избежать проблемы "PackageNotFoundException": кулак Вы не должны позволять пространству имен вашей модели NULL, определение пространства имен URI "nsURI" поможет идентифицировать модель Ecore в генераторах кода "XML-файлы", Так что, просто называя nsURI, любое имя будет соответствовать вашему EPackage. Также я переписываю xsi: circuitLocation="...." manulay, возможно, это не имеет смысла, но в конце концов это решает проблему