考虑使用eclipse生成的以下简单UML模型:
<?xml version="1.0" encoding="UTF-8"?>
<uml:Model xmi:version="20131001" xmlns:xmi="http://www.omg.org/spec/XMI/20131001" xmlns:uml="http://www.eclipse.org/uml2/5.0.0/UML" xmi:id="_qXjkkBojEeilO4QGIDh1YA" name="NewModel">
<packageImport xmi:id="_uR-ywBojEeilO4QGIDh1YA">
<importedPackage xmi:type="uml:Model" href="pathmap://UML_LIBRARIES/XMLPrimitiveTypes.library.uml#_0"/>
</packageImport>
<packagedElement xmi:type="uml:Class" xmi:id="_9ue9ABojEeilO4QGIDh1YA" name="Foo">
<ownedAttribute xmi:id="_DzKcQBokEeilO4QGIDh1YA" name="Bar">
<type xmi:type="uml:PrimitiveType" href="pathmap://UML_LIBRARIES/XMLPrimitiveTypes.library.uml#String"/>
</ownedAttribute>
</packagedElement>
</uml:Model>
我能够将此模型转换为UML&gt;的XSD。 ecore&gt; genmodel&gt; XSD通过 eclipse UI 路由。各中间结果如下:
E字形芯:
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="newModel" nsURI="http:///newModel.ecore" nsPrefix="newModel">
<eAnnotations source="http://www.eclipse.org/uml2/2.0.0/UML">
<details key="originalName" value="NewModel"/>
</eAnnotations>
<eClassifiers xsi:type="ecore:EClass" name="Foo">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="bar" ordered="false" lowerBound="1"
eType="ecore:EDataType http://www.eclipse.org/emf/2003/XMLType#//String">
<eAnnotations source="http://www.eclipse.org/uml2/2.0.0/UML">
<details key="originalName" value="Bar"/>
</eAnnotations>
</eStructuralFeatures>
</eClassifiers>
</ecore:EPackage>
的genmodel :
<?xml version="1.0" encoding="UTF-8"?>
<genmodel:GenModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
xmlns:genmodel="http://www.eclipse.org/emf/2002/GenModel" modelDirectory="/test/src" modelPluginID="test" modelName="NewModel"
rootExtendsClass="org.eclipse.emf.ecore.impl.MinimalEObjectImpl$Container" importerID="org.eclipse.emf.importer.ecore"
complianceLevel="5.0" copyrightFields="false" operationReflection="true" importOrganizing="true">
<foreignModel>../../foobar/newModel.ecore</foreignModel>
<genPackages prefix="NewModel" disposableProviderFactory="true" ecorePackage="newModel.ecore#/">
<genClasses ecoreClass="newModel.ecore#//Foo">
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute newModel.ecore#//Foo/bar"/>
</genClasses>
</genPackages>
</genmodel:GenModel>
最终结果 XSD :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:newModel="http:///newModel.ecore" xmlns:org.eclipse.uml2._2._0._0.uml="http://www.eclipse.org/uml2/2.0.0/UML" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ecore:nsPrefix="newModel" ecore:package="newModel" org.eclipse.uml2._2._0._0.uml:originalName="NewModel" targetNamespace="http:///newModel.ecore">
<xsd:element ecore:ignore="true" name="Foo" type="newModel:Foo"/>
<xsd:complexType name="Foo">
<xsd:attribute name="bar" org.eclipse.uml2._2._0._0.uml:originalName="Bar" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:schema>
此处,bar
的属性类型已正确识别为http://www.w3.org/2001/XMLSchema:string
,这是我的目标。
现在,我尝试使用Kotlin程序以编程方式生成相同的结果:
@file:JvmName("XsdGenerator")
package org.example.foo.bar
import org.eclipse.emf.codegen.ecore.genmodel.GenModelFactory
import org.eclipse.emf.common.util.URI
import org.eclipse.emf.ecore.EObject
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl
import org.eclipse.emf.ecore.util.EcoreUtil
import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl
import org.eclipse.uml2.uml.Model
import org.eclipse.uml2.uml.Namespace
import org.eclipse.uml2.uml.UMLPackage
import org.eclipse.uml2.uml.internal.resource.CMOF202UMLResourceImpl
import org.eclipse.uml2.uml.resource.UMLResource
import org.eclipse.uml2.uml.util.UMLUtil
import org.eclipse.xsd.ecore.EcoreSchemaBuilder
import org.eclipse.xsd.util.XSDResourceFactoryImpl
import kotlin.system.exitProcess
object XsdGenerator {
private val UML_LOAD_OPTIONS = emptyMap<String, String>()
private val UML_TO_ECORE_CONVERSION_OPTIONS = mutableMapOf<String, String>()
private val ECORE_RESOURCE_OPTIONS = mutableMapOf<String, String>()
private val GENMODEL_RESOURCE_OPTIONS = mutableMapOf<String, String>()
private val XSD_RESOURCE_OPTIONS = mutableMapOf<String, String>()
private lateinit var schemaSource: URI
private lateinit var buildDirectory: URI
private lateinit var schemaTarget: URI
private lateinit var schemaVersion: String
@JvmStatic
fun main(args: Array<String>) {
try {
schemaSource = URI.createFileURI(args[0])
buildDirectory = URI.createURI(args[1])
schemaTarget = URI.createURI(args[2])
schemaVersion = args[3]
} catch (e: Exception) {
println("Can't parse input arguments")
exitProcess(1)
}
val resources = ResourceSetImpl().apply {
resourceFactoryRegistry.apply {
extensionToFactoryMap["xsd"] = XSDResourceFactoryImpl()
extensionToFactoryMap["genmodel"] = EcoreResourceFactoryImpl()
extensionToFactoryMap["ecore"] = EcoreResourceFactoryImpl()
}
}
val umlModel = CMOF202UMLResourceImpl(schemaSource)
.apply {
if (!isLoaded) load(UML_LOAD_OPTIONS)
}
val ecoreModel = (EcoreUtil.getObjectByType(umlModel.contents, UMLPackage.Literals.MODEL) as Model)
.run {
UMLUtil.convertToEcore(this, UML_TO_ECORE_CONVERSION_OPTIONS)
}
.first()
.also {
resources
.createResource(buildDirectory.appendSegment("foobar.ecore"))
.apply {
contents.add(it)
save(ECORE_RESOURCE_OPTIONS)
}
}
val genPackages = GenModelFactory.eINSTANCE.createGenModel()
.also {
// genmodel settings can be set here
it.initialize(listOf(ecoreModel))
resources.createResource(buildDirectory.appendSegment("foobar.genmodel")).apply {
contents.add(it)
save(GENMODEL_RESOURCE_OPTIONS)
}
}
val mapBuilder = EcoreSchemaBuilder(genPackages.extendedMetaData)
val res = resources.resources.find { it.uri.toString().endsWith(".ecore") }
?: throw IllegalStateException("No ecore model present")
genPackages.allGenPackagesWithClassifiers.forEach { genPackage ->
val pack = genPackage.ecorePackage
val fileName = genPackage.nsName + ".xsd"
val xsdSchema = mapBuilder.getSchema(pack).apply {
version = schemaVersion
}
val xsdSchemaURI = res.uri.trimFileExtension().appendSegment(fileName)
resources.createResource(xsdSchemaURI).apply {
contents.add(xsdSchema)
save(XSD_RESOURCE_OPTIONS)
}
}
}
}
这给出了以下中间结果:
E字形芯:
<?xml version="1.0" encoding="UTF-8"?>
<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="NewModel" nsURI="http:///NewModel.ecore" nsPrefix="NewModel">
<eClassifiers xsi:type="ecore:EClass" name="Foo">
<eStructuralFeatures xsi:type="ecore:EAttribute" name="Bar" ordered="false" lowerBound="1"
eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EJavaObject"/>
</eClassifiers>
</ecore:EPackage>
的genmodel :
<?xml version="1.0" encoding="UTF-8"?>
<genmodel:GenModel xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore"
xmlns:genmodel="http://www.eclipse.org/emf/2002/GenModel" copyrightFields="false">
<genPackages prefix="NewModel" disposableProviderFactory="true" ecorePackage="/Users/mo/workspace/foobar/build/foobar.ecore#/">
<genClasses ecoreClass="/Users/mo/workspace/foobar/build/foobar.ecore#//Foo">
<genFeatures createChild="false" ecoreFeature="ecore:EAttribute /Users/mo/workspace/foobar/build/foobar.ecore#//Foo/Bar"/>
</genClasses>
</genPackages>
</genmodel:GenModel>
最后, XSD :
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns:NewModel="http:///NewModel.ecore" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ecore:nsPrefix="NewModel" ecore:package="NewModel" targetNamespace="http:///NewModel.ecore" version="0.0.1">
<xsd:import namespace="http://www.eclipse.org/emf/2002/Ecore" schemaLocation="http://www.eclipse.org/emf/2002/Ecore"/>
<xsd:element ecore:ignore="true" name="Foo" type="NewModel:Foo"/>
<xsd:complexType name="Foo">
<xsd:attribute ecore:name="Bar" name="Bar" type="ecore:EJavaObject" use="required"/>
</xsd:complexType>
</xsd:schema>
请注意,此处的类型信息会丢失,并且该属性的输入为ecore:EJavaObject
,而不是xsd:string
。
如何让我的程序保留XML模式类型与eclipse UI一样?