REPRESENTACIÓN DE UML EN OWL
Ejemplo ampliado desarrollado en el paper "An Open-Environmental Ontology Modeling"
Hemos estado trabajando en enfoques de transformación de modelos MDE de dos maneras: Transformaciones OWL2OWL y transformaciones UML2OWL. La primera (OWL2OWL) permite al sistema transformar plantillas EIM (es decir, la representación OWL para el modelado del conocimiento ontológico de SOLERES) en plantillas EID (es decir, la representación OWL para utilizar servicios de comercio en el sistema SOLERES); la segunda (UML2OWL) nos permite transformar representaciones UML del modelo de conocimiento ontológico (plantillas EIM formalizadas en notación UML) en plantillas OWL.
En esta sección nos centraremos en explicar el proceso de transformación de este último, mapeando modelos UML a código OWL mediante transformación de modelos, aunque la técnica de transformación es la misma en ambos casos.
Contenido
-
Un estudio de caso para la transformación de modelos ontológicos
2.1. Escenario de ejemplo
2.2. Tipos de datos
2.3. UML2OWL -
Proceso de transformación
3.1. Reglas UML2OWL- Model2Graph
- Package2Ontology
- UMLClass2OWLClass
- DataType2RDFSDataType
- Property2DataTypeProperty
- Property2InverseObjectProperty
- Property2InverseFunctionalProperty
- addFunctionalProperty
- addCardinality
- addMinCardinality
3.2. Reglas OWL2XML
- Model2Graph
Transformación de modelos
La transformación de modelos es un marco general de la ingeniería de software en el que algunos modelos (visuales) se transforman en otros modelos. En UML los modelos representan instancias de diagramas UML (diagramas de clases, máquinas de estados, diagramas de secuencia, etc.); dichas instancias pueden transformarse para tener diferentes vistas de un mismo modelo, o para obtener código en un lenguaje de programación concreto, entre otros ejemplos.
Existen transformaciones M2M, para transformaciones de modelo a modelo, y M2T, para transformaciones de "modelo a texto" (es decir, de un diagrama de clases UML a código). La propuesta MDA (Model-Driven Architecture) de OMG (Object Management Group) presenta un proceso de desarrollo de software para apoyar el desarrollo de sistemas. Los conceptos más importantes son los modelos y las transformaciones entre ellos, que a su vez crean otros modelos. La descripción de las transformaciones de modelos requiere un lenguaje específico para sus definiciones. En la mayoría de los casos, las transformaciones pueden expresarse mediante algunas reglas. Las reglas deben mostrar cómo un modelo dado puede transformarse en otro.
En la literatura existen varias propuestas de lenguajes y herramientas de transformación. El lenguaje QTV (Query-View-Transformation) está en el contexto de MOF (Meta Object Facility). Este lenguaje se propuso como estándar para la transformación de modelos. El lenguaje ATL (ATLAS Transformation Language) es un lenguaje específico de dominio (DSL) para especificar transformaciones de modelos. ATL está inspirado en QVT. ATL es un lenguaje híbrido que permite construcciones tanto declarativas como imperativas. Otras propuestas híbridas para la transformación de modelos son, por ejemplo, RubyTL y MT.
Para nuestro propósito, decidimos utilizar el lenguaje ATL para la transformación de modelos porque es una implementación bien conocida y se basa en el estándar QVT de MOF/OMG. Para implementar nuestros transformadores, utilizamos la plataforma Eclipse. En concreto, utilizamos el paquete Eclipse Modeling Project, una colección de herramientas útiles (EMF, GMF, MDT, M2M, etc.) para el modelado. Por lo tanto, todos los transformadores desarrollados para nuestros fines de investigación se han implementado en esta plataforma en ATL. Sin embargo, para las transformaciones UML2OWL (en las que se realiza una representación del modelo ontológico para transformar UML a OWL), utilizamos un componente de código abierto (plugin) de Eclipse que implementa la facilidad ODM/OMG (Ontology Definition Metamodel). Este plugin es muy útil para transformaciones UML2OWL sencillas; sin embargo, presenta ciertas carencias para tipos de datos complejos. Aquí, ampliamos esta implementación de Eclipse para incluir tipos de datos complejos EML y GML y adaptar el mapeo para transformaciones ontológico-modelo. A continuación, explicaremos algunos detalles de la implementación y el proceso de transformación a través de un caso práctico.
Un estudio de caso para la transformación de modelos ontológicos
La ontología (como metamodelo) se construye una sola vez y luego los diseñadores pueden especializar el metamodelo según sus necesidades. La colección de modelos ontológicos UML (y sus posibles variaciones) podría traducirse automáticamente a un modelo textual OWL mediante una herramienta M2T (Model-to-Text). Nos centraremos en explicar algunas correspondencias entre algunos elementos del modelo visual UML y el modelo textual OWL.
Escenario de ejemplo
Para explicar la transformación, podemos ver el ejemplo en la siguiente figura. Aquí, podemos ver cómo la misma rejilla (Grid en la figura) se utiliza para más de una clasificación ecológica.

Por ejemplo, en nuestro ejemplo utilizaremos la misma Grid (con 21.905 celdas) para obtener los mapas ecológicos de clasificación de la climatología, litología, geomorfología, suelos edáficos y vegetación (mapas del 1 al 5); cinco mapas para la misma Grid. En Ecología, una "cuadrícula" viene determinada por
- (a) el tamaño de la celda (cell_size_X, cell_size_Y)
- (b) el número de filas (row_size)
- (c) el número de columnas (column_size)
- (d) las coordenadas UTM para la georreferenciación de la cuadrícula (georef_utm)
Tipos de datos
En el modelo UML anterior sólo incluimos el nombre de los atributos, pero todos los atributos de las clases se definen mediante tipos de datos en los modelos. Por ejemplo, en la figura anterior los tipos de datos se representan como "name:DataType". Los tipos de datos Entero y Cadena son tipos base. En la clase Grid hay cinco tipos de datos (cellSizeXDirection, cellSizeYDirection, rows, columns, georeferenceInfo) que están definidos en la gramática eml-spatialRaster.xsd del paquete EML. Por lo tanto, la clase Grid utiliza la clase EML con el nombre de esquema contenido en la gramática. Esto se define en UML mediante una relación de dependencia entre ambas clases. Cada tipo de dato EML, a su vez, puede dividirse en algunos otros tipos, aunque esto se definirá en la gramática referenciada. Por ejemplo, el tipo de dato georeferenceInfo tiene los elementos requeridos de un Grid georeferenceInfo de un mapa cartográfico, como son las coordenadas de georreferenciación en el espacio (xCoordinate y yCoordinate) y una esquina (corner), por lo que puede tomar los valores "center", "lowerRight", "lowerLeft", "upperRight" o "upperLeft" en su instanciación.
UML2OWL
Utilizamos una herramienta de código abierto de Eclipse adaptada a nuestro propósito y ampliada a tipos de datos complejos. El proceso de transformación se ejecuta en dos etapas. En la primera se transforma el modelo original (véase 2.2) en una representación intermedia de OWL: una instanciación del metamodelo OWL escrita en XMI.En la segunda etapa, la representación intermedia se transforma en XML (código final de OWL):

La siguiente figura muestra la representación intermedia generada en la primera etapa. El diagrama es un perfil UML para OWL. Las clases del modelo de entrada se representan en el modelo intermedio mediante clases estereotipadas "owlClass" (y luego como elementos owl:Class en el modelo de destino). Lo mismo ocurre con los tipos de datos primitivos (por ejemplo, "String" o "Integer") de los atributos de clase, que de nuevo vienen como atributos de clase estereotipados como "datatypeProperty". Sin embargo, para los tipos de datos complejos, la etapa intermedia genera nuevos tipos de datos vinculados al paquete que los define. Por ejemplo, la propiedad "georef_utm" se define en el modelo de entrada (Figura en 2.2 como un atributo de clase con el tipo "georeferenceInfo" (es decir, georef_utm: georeferenceInfo). En el modelo intermedio, dicha propiedad se representa mediante dos clases asociadas y estereotipadas: una para el atributo (datatypeProperty) y otra para el tipo (dataType). El transformador incluye un enlace al paquete eml-spatialRaster.xd para las tareas de mapeo.Por último, la asociación en el modelo intermedio se etiqueta con los elementos tradicionales de OWL "has" e "inverseOf".

El proceso de transformación del modelo requiere un modelo UML de origen escrito en formato XMI (por ejemplo, "ejemplo.uml"); también genera un modelo OWL de destino en formato XML (por ejemplo, "ejemplo.owl"): transformación M2M endógena. La siguiente figura muestra el archivo XMI del modelo UML fuente:

Ahora, podemos ver el fichero XML del modelo OWL destino: transformación M2T exógena:

Proceso de transformación
Reglas UML2OWL
En esta sección, explicamos el proceso completo de transformación. Esta transformación comienza con el modelo UML del ejemplo presentado anteriormente:
<?xml version="1.0" encoding="UTF-8"?>
<uml:Model xmi:version="2.1" xmlns:xmi="http://schema.omg.org/spec/XMI/2.1"
xmlns:uml="http://www.eclipse.org/uml2/2.1.0/UML"
xmi:id="_qb8akM37EdqwVrslYOdUDA" name="ontology">
<packagedElement xmi:type="uml:Package" xmi:id="_w8IxIM37EdqwVrslYOdUDA"
name="http://www.ual.es/acg/soleres/ontology">
<packagedElement xmi:type="uml:Class" xmi:id="_3dw8YKx5EduvtrQ7BMslhA"
name="Ecological_classification">
<ownedAttribute xmi:id="_MfAK8DAxEd--IoYfZcCMlg" name="id"
type="_LbFmcKx6EduvtrQ7BMslhA" aggregation="composite"/>
<ownedAttribute xmi:id="_Nx2S4DAxEd--IoYfZcCMlg" name="name"
type="_LbFmcax6EduvtrQ7BMslhA" aggregation="composite"/>
<ownedAttribute xmi:id="_OcBRQDAxEd--IoYfZcCMlg" name="description"
type="_LbFmcax6EduvtrQ7BMslhA" aggregation="composite"/>
<ownedAttribute xmi:id="_POYiUDAxEd--IoYfZcCMlg" name="observations"
type="_LbFmcax6EduvtrQ7BMslhA" aggregation="composite"/>
</packagedElement>
<packagedElement xmi:type="uml:Class" xmi:id="_4xgcMKx5EduvtrQ7BMslhA"
name="Grid">
<ownedAttribute xmi:id="_fzf6cDAxEd--IoYfZcCMlg" name="id"
type="_LbFmcKx6EduvtrQ7BMslhA" aggregation="composite"/>
<ownedAttribute xmi:id="_eSBjwDD5Ed-YotXu97PIsA" name="cell_size_X"
type="_W5tDgDKHEd-yToNOK4bJsQ" aggregation="composite"/>
<ownedAttribute xmi:id="_hG7UUDD5Ed-YotXu97PIsA" name="cell_size_Y"
type="_b6rDADKHEd-yToNOK4bJsQ" aggregation="composite"/>
<ownedAttribute xmi:id="_iX_TkDD5Ed-YotXu97PIsA" name="row_size"
type="_kpKdIDKHEd-yToNOK4bJsQ" aggregation="composite"/>
<ownedAttribute xmi:id="_l1RSwDD5Ed-YotXu97PIsA" name="column_size"
type="_mvuhADKHEd-yToNOK4bJsQ" aggregation="composite"/>
<ownedAttribute xmi:id="\_npC9gDD5Ed-YotXu97PIsA" name="georef_utm"
type="_-V-9cDKDEd-yToNOK4bJsQ" aggregation="composite"/>
</packagedElement>
<packagedElement xmi:type="uml:Association" xmi:id="_TgFdgDAwEd--IoYfZcCMlg"
name="A_-_Ecological_classification-Grid"
memberEnd="_TgFdgTAwEd--IoYfZcCMlg _TgFdhDAwEd--IoYfZcCMlg">
<ownedEnd xmi:id="_TgFdgTAwEd--IoYfZcCMlg"
name="has_ecological_classification" type="_3dw8YKx5EduvtrQ7BMslhA"
association="_TgFdgDAwEd--IoYfZcCMlg">
<upperValue xmi:type="uml:LiteralUnlimitedNatural"
xmi:id="_TgFdgzAwEd--IoYfZcCMlg" value="*"/>
<lowerValue xmi:type="uml:LiteralInteger"
xmi:id="_TgFdgjAwEd--IoYfZcCMlg" value="1"/>
</ownedEnd>
<ownedEnd xmi:id="_TgFdhDAwEd--IoYfZcCMlg" name="has_grid"
type="_4xgcMKx5EduvtrQ7BMslhA" aggregation="composite"
association="_TgFdgDAwEd--IoYfZcCMlg">
<upperValue xmi:type="uml:LiteralUnlimitedNatural"
xmi:id="_TgFdhjAwEd--IoYfZcCMlg" value="1"/>
<lowerValue xmi:type="uml:LiteralInteger"
xmi:id="_TgFdhTAwEd--IoYfZcCMlg" value="1"/>
</ownedEnd>
</packagedElement>
<packagedElement xmi:type="uml:DataType" xmi:id="_-V-9cDKDEd-yToNOK4bJsQ"
name="georeferenceInfo"/>
<packagedElement xmi:type="uml:DataType" xmi:id="_W5tDgDKHEd-yToNOK4bJsQ"
name="cellSizeXDirection"/>
<packagedElement xmi:type="uml:DataType" xmi:id="_b6rDADKHEd-yToNOK4bJsQ"
name="cellSizeYDirection"/>
<packagedElement xmi:type="uml:DataType" xmi:id="_kpKdIDKHEd-yToNOK4bJsQ"
name="rows"/>
<packagedElement xmi:type="uml:DataType" xmi:id="_mvuhADKHEd-yToNOK4bJsQ"
name="columns"/>
</packagedElement>
<packagedElement xmi:type="uml:PrimitiveType" xmi:id="_La8cgKx6EduvtrQ7BMslhA"
name="Boolean"/>
<packagedElement xmi:type="uml:PrimitiveType" xmi:id="_LbFmcKx6EduvtrQ7BMslhA"
name="Integer"/>
<packagedElement xmi:type="uml:PrimitiveType" xmi:id="_LbFmcax6EduvtrQ7BMslhA"
name="String"/>
<packagedElement xmi:type="uml:PrimitiveType" xmi:id="_LbFmcqx6EduvtrQ7BMslhA"
name="UnlimitedNatural"/>
</uml:Model>
A continuación, mostramos las reglas aplicadas por la transformación UML2OWL (véase 2.3). Estas reglas se aplican en el modelo UML para obtener el concepto correspondiente en el modelo OWL. Así, la transformación UML2OWL.atl tiene como entrada el fichero example.uml y construye como salida el example-OWL.ecore.
Model2Graph
Transforma el elemento "Model" del modelo UML en el elemento "OWLGraph" del modelo OWL.
rule Model2Graph {
from
m: UML!Model (
m.oclIsTypeOf(UML!Model)
)
to
g : OWL!OWLGraph (
ontology <- m.packagedElement->select(e | e.oclIsTypeOf(UML!Package)),
uriRef <- uri
),
d : OWL!Document (
namespaceDefinition <- nd,
localName <- ln,
xmlBase <- xb
),
ln : OWL!LocalName (
name <- m.name,
uriRef <- uri
),
uri : OWL!URIReference (
uri <- u_r_i
),
u_r_i : OWL!UniformResourceIdentifier (
name <- thisModule.addNamespace(m.name)
),
xb : OWL!Namespace (
namespaceURIRef <- uri
),
nd : OWL!NamespaceDefinition (
namespacePrefix <- thisModule.addNamespace(m.name),
namespace <- xb
)
}
Código de origen:
<uml:Model xmi:version="2.1"
xmlns:xmi="http://schema.omg.org/spec/XMI/2.1"
xmlns:uml="http://www.eclipse.org/uml2/2.1.0/UML"
xmi:id="_qb8akM37EdqwVrslYOdUDA" name="ontology">
Código generado:
<OWLGraph ontology="/4">
<uriRef uri="/2" fragmentIdentifier="/1/@localName.0" namespace="/3"/>
</OWLGraph>
<_1:Document xmlBase="/3">
<localName name="ontology" uriRef="/0/@uriRef.0"/>
<namespaceDefinition namespacePrefix="ontology" namespace="/3"/>
</_1:Document>
<_1:UniformResourceIdentifier name="ontology" uriRef="/0/@uriRef.0"/>
<_1:Namespace document="/1" namespaceURIRef="/0/@uriRef.0"
namespaceDefinition="/1/@namespaceDefinition.0"/>
Package2Ontology
Transforma el elemento "Package" del modelo UML en el elemento "Ontology" del modelo OWL.
rule Package2Ontology {
from
p : UML!Package (
p.oclIsTypeOf(UML!Package)
)
to
o : OWL!OWLOntology (
uriRef <- u,
OWLImports <- p.packageImport->collect( e | e.importedPackage ),
owlGraph <- UML!Model.allInstances()->asSequence()
->any( m | m.oclIsTypeOf(UML!Model)),
owlUniverse <- p.packagedElement
),
u : OWL!URIReference ( fragmentIdentifier <- l, uri <- uri ),
l : OWL!LocalName ( name <- p.name ),
uri : OWL!UniformResourceIdentifier (
name <- thisModule.addNamespace(p.name)
)
}
Código generado:
<OWLOntology owlUniverse="/7 /10" owlGraph="/0">
<uriRef uri="/6" fragmentIdentifier="/5"/>
</OWLOntology>
<_1:LocalName name="http://www.ual.es/acg/soleres/ontology" uriRef="/4/@uriRef.0"/>
<_1:UniformResourceIdentifier name="http://www.ual.es/acg/soleres/ontology"
uriRef="/4/@uriRef.0"/>
UMLClass2OWLClass
Transforma el elemento "Class" del modelo UML en el elemento "OWLClass" del modelo OWL.
rule UMLClass2OWLClass {
from
c : UML!Class (
c.oclIsTypeOf(UML!Class) and
not thisModule.sequenceOfUnionClass.includes(c)
)
to
oc : OWL!OWLClass (
subClassOf <- c.general,
uriRef <- u,
label <- label
),
label : OWL!PlainLiteral (
lexicalForm <- c.name
),
u : OWL!URIReference (
fragmentIdentifier <- l,uri <- uri
),
l : OWL!LocalName (
name <- c.name
),
uri : OWL!UniformResourceIdentifier (
name <- c.name
)
}
Ejemplo de código de origen:
<packagedElement xmi:type="uml:Class" xmi:id="_3dw8YKx5EduvtrQ7BMslhA" name="Ecological_classification">
Ejemplo de código generado:
<OWLClass subClassOf="/69 /71 /73 /75 /90" propertyForDomain="/33 /36 /39 /42 /63"
propertyForRange="/66" ontology="/4">
<uriRef uri="/9" fragmentIdentifier="/8"/>
<label lexicalForm="Ecological_classification"/>
</OWLClass>
<_1:LocalName name="Ecological_classification" uriRef="/7/@uriRef.0"/>
<_1:UniformResourceIdentifier name="Ecological_classification" uriRef="/7/@uriRef.0"/>
DataType2RDFSDataType
Transforma los elementos "Datatype" del modelo UML al elemento "RDFSDataType" del modelo OWL, mapeando los tipos definidos del modelo.
rule DataType2RDFSDataType {
from
p : UML!Datatype
to
d : OWL!RDFSDataType (
uriRef <- u
),
u : OWL!URIReference (
uri <- uri
),
uri : OWL!UniformResourceIdentifier (
name <- thisModule.typeMap.get(p.name)
)
}
(regla helper utilizada):
helper def: typeMap : Map(String, String) =
Map {
('String', 'xsd:string'),
('Integer', 'xsd:nonNegativeInteger'),
('Boolean', 'xsd:boolean'),
('UnlimitedNatural', 'xsd:integer' ),
('cellSizeXDirection', 'eml:cellSizeXDirection' ),
('cellSizeYDirection', 'eml:cellSizeYDirection' ),
('rows', 'eml:rows' ),
('columns', 'eml:columns' ),
('georeferenceInfo', 'eml:georeferenceInfo' )
};
Ejemplo de código de origen (tipo String):
<packagedElement xmi:type="uml:PrimitiveType" xmi:id="_LbFmcax6EduvtrQ7BMslhA"
name="String"/>
(and this code)
<packagedElement xmi:type="uml:Package" xmi:id="_w8IxIM37EdqwVrslYOdUDA"
name="http://www.ual.es/acg/soleres/ontology">
<packagedElement xmi:type="uml:Class" xmi:id="_3dw8YKx5EduvtrQ7BMslhA"
name="Ecological_classification">
<ownedAttribute xmi:id="_MfAK8DAxEd--IoYfZcCMlg" name="id"
type="_LbFmcKx6EduvtrQ7BMslhA" aggregation="composite"/>
<ownedAttribute xmi:id="_Nx2S4DAxEd--IoYfZcCMlg" name="name"
type="_LbFmcax6EduvtrQ7BMslhA" aggregation="composite"/>
<ownedAttribute xmi:id="_OcBRQDAxEd--IoYfZcCMlg" name="description"
type="_LbFmcax6EduvtrQ7BMslhA" aggregation="composite"/>
<ownedAttribute xmi:id="_POYiUDAxEd--IoYfZcCMlg" name="observations"
type="_LbFmcax6EduvtrQ7BMslhA" aggregation="composite"/>
Ejemplo de código generado:
<_1:RDFSDataType propertyForRange="/36 /39 /42">
<uriRef uri="/18"/>
</_1:RDFSDataType>
<_1:UniformResourceIdentifier name="xsd:string" uriRef="/17/@uriRef.0"/>
Ejemplo de código de origen (tipo georeferenceInfo):
<packagedElement xmi:type="uml:DataType" xmi:id="_-V-9cDKDEd-yToNOK4bJsQ"
name="georeferenceInfo"/>
(and this code)
<packagedElement xmi:type="uml:Class" xmi:id="_4xgcMKx5EduvtrQ7BMslhA"
name="Grid">
<ownedAttribute xmi:id="_fzf6cDAxEd--IoYfZcCMlg" name="id"
type="_LbFmcKx6EduvtrQ7BMslhA" aggregation="composite"/>
<ownedAttribute xmi:id="_eSBjwDD5Ed-YotXu97PIsA" name="cell_size_X"
type="_W5tDgDKHEd-yToNOK4bJsQ" aggregation="composite"/>
<ownedAttribute xmi:id="_hG7UUDD5Ed-YotXu97PIsA" name="cell_size_Y"
type="_b6rDADKHEd-yToNOK4bJsQ" aggregation="composite"/>
<ownedAttribute xmi:id="_iX_TkDD5Ed-YotXu97PIsA" name="row_size"
type="_kpKdIDKHEd-yToNOK4bJsQ" aggregation="composite"/>
<ownedAttribute xmi:id="_l1RSwDD5Ed-YotXu97PIsA" name="column_size"
type="_mvuhADKHEd-yToNOK4bJsQ" aggregation="composite"/>
<ownedAttribute xmi:id="_npC9gDD5Ed-YotXu97PIsA" name="georef_utm"
type="_-V-9cDKDEd-yToNOK4bJsQ" aggregation="composite"/>
Ejemplo de código generado:
<_1:RDFSDataType propertyForRange="/58">
<resource href="/UML2OWL/Samples/OWLModels/example-OWL.ecore#/4"/>
<uriRef uri="/14"/>
</_1:RDFSDataType>
<_1:UniformResourceIdentifier name="eml:georeferenceInfo" uriRef="/13/@uriRef.0"/>
Property2DatatypeProperty
Transforma un elemento "Property" que es un "PrimitiveType" o un "DataType" en un elemento "OWLDatypeProperty". Además, llama a reglas de ayuda para añadir restricciones de cardinalidad si es necesario.
rule Property2DatatypeProperty {
from
p : UML!Property (
p.type.oclIsTypeOf(UML!PrimitiveType) or p.type.oclIsTypeOf(UML!DataType)
)
to
d : OWL!OWLDatatypeProperty (
uriRef <- u,
domain <- p.class,
range <- p.type
),
u : OWL!URIReference ( fragmentIdentifier <- l, uri <- uri ),
l : OWL!LocalName ( name <- p.class.name + '.' + p.name ),
uri : OWL!UniformResourceIdentifier ( name <- p.class.name + '.' + p.name )
do {
if ( p.upper = p.lower ) -- [n-n]
thisModule.addCardinalityRestriction( p );
else if (( p.upper = 0-1 ) and ( p.lower >= 0 )) -- [*]
thisModule.addMinCardinalityRestriction( p );
else { -- [m-n]
thisModule.addMinCardinalityRestriction( p );
thisModule.addMaxCardinalityRestriction( p );
}
}
}
Ejemplo de código de origen:
<ownedAttribute xmi:id="_npC9gDD5Ed-YotXu97PIsA" name="georef_utm" type="_pxx2gDD3Ed-YotXu97PIsA" aggregation="composite"/>
Ejemplo de código generado:
<OWLDatatypeProperty domain="/10" range="/23" propertyRestriction="/87">
<uriRef uri="/62" fragmentIdentifier="/61"/>
</OWLDatatypeProperty>
<_1:LocalName name="Grid.georef_utm" uriRef="/60/@uriRef.0"/>
<_1:UniformResourceIdentifier name="Grid.georef_utm" uriRef="/60/@uriRef.0"/>
Property2InverseObjectProperty
Transforma un elemento "Property" que es un "PrimitiveType", tiene una asociación binaria que no es de tipo "Class", y la propiedad no era de tipo "InverseFunctional". La salida de la transformación es un elemento "OWLObjectProperty" del modelo OWL. Además, llama a reglas de ayuda para añadir restricciones de cardinalidad si es necesario.
rule Property2InverseObjectProperty {
from
p : UML!Property (
not (p.type.oclIsTypeOf(UML!PrimitiveType))
and if (p.association.oclIsUndefined())
then false
else if (p.association.isBinary() and not (p.association.oclIsKindOf(UML!Class)))
then (not p.isSymmetric() and not p.isInverseFunctional())
else false
endif
endif
)
using {
inverse : UML!Property =
p.association.ownedEnd->asSequence()
->any( e | e.oclIsTypeOf(UML!Property) and not (e = p));
}
to
o : OWL!OWLObjectProperty (
domain <- inverse.type,
range <- p.type,
OWLInverseOf <- inverse,
uriRef <- o_u,
subPropertyOf <- p.redefinedProperty
),
o_u : OWL!URIReference (
fragmentIdentifier <- o_l,
uri <- o_uri
),
o_l : OWL!LocalName (
name <- inverse.type.name + '.' + p.name
),
o_uri : OWL!UniformResourceIdentifier (
name <- inverse.type.name + '.' + p.name
)
do {
if ( ( p.upper = 1) and ( p.lower = 1) )
thisModule.addFunctionalProperty( p );
if ( p.upper = p.lower ) -- [n-n]
thisModule.addCardinality( p, inverse.type );
else
if (( p.upper = 0-1 ) and ( p.lower >= 0 )) -- [*]
thisModule.addMinCardinality( p, inverse.type );
else {-- [m-n]
thisModule.addMinCardinality( p, inverse.type );
thisModule.addMaxCardinality( p, inverse.type );
}
}
}
Código de origen:
<packagedElement xmi:type="uml:Association" xmi:id="_TgFdgDAwEd--IoYfZcCMlg" name="A_-_Ecological_classification-Grid" memberEnd="_TgFdgTAwEd--IoYfZcCMlg _TgFdhDAwEd--IoYfZcCMlg">
<ownedEnd xmi:id="_TgFdgTAwEd--IoYfZcCMlg" name="has_ecological_classification" type="_3dw8YKx5EduvtrQ7BMslhA" association="_TgFdgDAwEd--IoYfZcCMlg">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_TgFdgzAwEd--IoYfZcCMlg" value="*"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_TgFdgjAwEd--IoYfZcCMlg" value="1"/>
</ownedEnd>
<ownedEnd xmi:id="_TgFdhDAwEd--IoYfZcCMlg" name="has_grid" type="_4xgcMKx5EduvtrQ7BMslhA" aggregation="composite" association="_TgFdgDAwEd--IoYfZcCMlg">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_TgFdhjAwEd--IoYfZcCMlg" value="1"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_TgFdhTAwEd--IoYfZcCMlg" value="1"/>
</ownedEnd>
Código generado:
<OWLObjectProperty definedResource="/89" domain="/7" range="/10" propertyRestriction="/90" OWLInverseOf="/66" inverseProperty="/66">
<uriRef uri="/65" fragmentIdentifier="/64"/>
</OWLObjectProperty>
<_1:LocalName name="Ecological_classification.has_grid" uriRef="/63/@uriRef.0"/>
<_1:UniformResourceIdentifier name="Ecological_classification.has_grid" uriRef="/63/@uriRef.0"/>
Property2InverseFunctionalProperty
Transforma un elemento "Property" que es un "PrimitiveType", tiene una asociación binaria que no es de tipo "Class", y la propiedad era de tipo "InverseFuncional". La salida de la transformación es una "InverseFuncionalProperty" del modelo OWL. Además, llama a reglas de ayuda para añadir restricciones de cardinalidad si es necesario.
rule Property2InverseFunctionalProperty {
from
p : UML!Property (
not (p.type.oclIsTypeOf(UML!PrimitiveType))
and if (p.association.oclIsUndefined())
then false
else if (p.association.isBinary() and not (p.association.oclIsKindOf(UML!Class)))
then (p.isInverseFunctional() and not p.isSymmetric())
else false
endif
endif
)
using {
inverse : UML!Property =
p.association.ownedEnd->asSequence()
->any( e | e.oclIsTypeOf(UML!Property) and not (e = p));
}
to
o : OWL!InverseFunctionalProperty (
domain <- inverse.type,
range <- p.type,
OWLInverseOf <- inverse,
uriRef <- o_u,
subPropertyOf <- p.redefinedProperty
),
o_u : OWL!URIReference (
fragmentIdentifier <- o_l,
uri <- o_uri
),
o_l : OWL!LocalName (
name <- inverse.type.name + '.' + p.name
),
o_uri : OWL!UniformResourceIdentifier (
name <- inverse.type.name + '.' + p.name
)
do {
if ( ( p.upper = 1) and ( p.lower = 1) )
thisModule.addFunctionalProperty( p );
if ( p.upper = p.lower ) -- [n-n]
thisModule.addCardinality( p, inverse.type );
else
if (( p.upper = 0-1 ) and ( p.lower >= 0 )) -- [*]
thisModule.addMinCardinality( p, inverse.type );
else {-- [m-n]
thisModule.addMinCardinality( p, inverse.type );
thisModule.addMaxCardinality( p, inverse.type );
}
}
}
Código de origen:
<packagedElement xmi:type="uml:Association" xmi:id="_TgFdgDAwEd--IoYfZcCMlg" name="A_-_Ecological_classification-Grid" memberEnd="_TgFdgTAwEd--IoYfZcCMlg _TgFdhDAwEd--IoYfZcCMlg">
<ownedEnd xmi:id="_TgFdgTAwEd--IoYfZcCMlg" name="has_ecological_classification" type="_3dw8YKx5EduvtrQ7BMslhA" association="_TgFdgDAwEd--IoYfZcCMlg">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_TgFdgzAwEd--IoYfZcCMlg" value="*"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_TgFdgjAwEd--IoYfZcCMlg" value="1"/>
</ownedEnd>
<ownedEnd xmi:id="_TgFdhDAwEd--IoYfZcCMlg" name="has_grid" type="_4xgcMKx5EduvtrQ7BMslhA" aggregation="composite" association="_TgFdgDAwEd--IoYfZcCMlg">
<upperValue xmi:type="uml:LiteralUnlimitedNatural" xmi:id="_TgFdhjAwEd--IoYfZcCMlg" value="1"/>
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="_TgFdhTAwEd--IoYfZcCMlg" value="1"/>
</ownedEnd>
Código generado:
<InverseFunctionalProperty domain="/10" range="/7" propertyRestriction="/92" OWLInverseOf="/63" inverseProperty="/63">
<uriRef uri="/68" fragmentIdentifier="/67"/>
</InverseFunctionalProperty>
<_1:LocalName name="Grid.has_ecological_classification" uriRef="/66/@uriRef.0"/>
<_1:UniformResourceIdentifier name="Grid.has_ecological_classification" uriRef="/66/@uriRef.0"/>
addFunctionalProperty
Transforma un elemento "Property" del modelo UML en un elemento "FunctionalProperty" del modelo OWL.
rule addFunctionalProperty( p : UML!Property ) {
to
o : OWL!FunctionalProperty (
isDefinedBy <- p
)
}
Código generado:
<FunctionalProperty isDefinedBy="/63"/>
addCardinality
Esta regla añade una restricción de cardinalidad exacta a la propiedad y a la clase indicadas por parámetro:
rule addCardinality( p : UML!Property, class : UML!Class ) {
to
c : OWL!CardinalityRestriction (
superClass <- class,
OWLCardinality <- literal,
OWLOnProperty <- p
),
literal : OWL!TypedLiteral (
lexicalForm <- p.upper.toString(),
datatypeURI <- thisModule.getIntegerURI()
)
}
Ejemplo de código generado:
<CardinalityRestriction superClass="/7" OWLOnProperty="/33" OWLCardinality="/70"/>
<_1:TypedLiteral lexicalForm="1" datatypeURI="/15/@uriRef.0" cardinalityRestriction="/69"/>
addMinCardinality
Esta regla añade una restricción de cardinalidad mínima a la propiedad y a la clase indicada por el parámetro:
rule addMinCardinality( p : UML!Property, class : UML!Class ) {
to
c : OWL!MinCardinalityRestriction (
superClass <- class,
OWLMinCardinality <- literal,
OWLOnProperty <- p
),
literal : OWL!TypedLiteral (
lexicalForm <- p.lower.toString(),
datatypeURI <- thisModule.getIntegerURI()
)
}
Ejemplo de código generado:
<MinCardinalityRestriction superClass="/10" OWLOnProperty="/66" OWLMinCardinality="/93"/>
<_1:TypedLiteral lexicalForm="1" datatypeURI="/15/@uriRef.0" minCardinalityRestriction="/92"/>
Reglas OWL2XML
Una vez ejecutadas todas las reglas del fichero de transformación UML2OWL.atl, obtenemos el modelo OWL. Este es el código del fichero "ejemplo-OWL.ecore"
<?xml version="1.0" encoding="ISO-8859-1"?>
<xmi:XMI xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns="OWL" xmlns:_1="RDFS">
<OWLGraph ontology="/4">
<uriRef uri="/2" fragmentIdentifier="/1/@localName.0" namespace="/3" />
</OWLGraph>
<_1:Document xmlBase="/3">
<localName name="ontology" uriRef="/0/@uriRef.0" />
<namespaceDefinition namespacePrefix="ontology" namespace="/3" />
</_1:Document>
<_1:UniformResourceIdentifier name="ontology" uriRef="/0/@uriRef.0" />
<_1:Namespace document="/1" namespaceURIRef="/0/@uriRef.0"
namespaceDefinition="/1/@namespaceDefinition.0" />
<OWLOntology owlUniverse="/7 /10 /13 /15 /17 /19 /21" owlGraph="/0">
<uriRef uri="/6" fragmentIdentifier="/5" />
</OWLOntology>
<_1:LocalName name="http://www.ual.es/acg/soleres/ontology" uriRef="/4/@uriRef.0" />
<_1:UniformResourceIdentifier name="http://www.ual.es/acg/soleres/ontology"
uriRef="/4/@uriRef.0" />
<OWLClass subClassOf="/67 /69 /71 /73 /88" propertyForDomain="/31 /34 /37 /40 /61"
propertyForRange="/64" ontology="/4">
<uriRef uri="/9" fragmentIdentifier="/8" />
<label lexicalForm="Ecological_classification" />
</OWLClass>
<_1:LocalName name="Ecological_classification" uriRef="/7/@uriRef.0" />
<_1:UniformResourceIdentifier name="Ecological_classification" uriRef="/7/@uriRef.0" />
<OWLClass subClassOf="/75 /77 /79 /81 /83 /85 /90"
propertyForDomain="/43 /46 /49 /52 /55 /58 /64" propertyForRange="/61" ontology="/4">
<uriRef uri="/12" fragmentIdentifier="/11" />
<label lexicalForm="Grid" />
</OWLClass>
<_1:LocalName name="Grid" uriRef="/10/@uriRef.0" />
<_1:UniformResourceIdentifier name="Grid" uriRef="/10/@uriRef.0" />
<_1:RDFSDataType propertyForRange="/58">
<resource href="/UML2OWL/Samples/OWLModels/example_2-OWL.ecore#/4" />
<uriRef uri="/14" />
</_1:RDFSDataType>
<_1:UniformResourceIdentifier name="eml:georeferenceInfo" uriRef="/13/@uriRef.0" />
<_1:RDFSDataType propertyForRange="/46">
<resource href="/UML2OWL/Samples/OWLModels/example_2-OWL.ecore#/4" />
<uriRef uri="/16" />
</_1:RDFSDataType>
<_1:UniformResourceIdentifier name="eml:cellSizeXDirection" uriRef="/15/@uriRef.0" />
<_1:RDFSDataType propertyForRange="/49">
<resource href="/UML2OWL/Samples/OWLModels/example_2-OWL.ecore#/4" />
<uriRef uri="/18" />
</_1:RDFSDataType>
<_1:UniformResourceIdentifier name="eml:cellSizeYDirection" uriRef="/17/@uriRef.0" />
<_1:RDFSDataType propertyForRange="/52">
<resource href="/UML2OWL/Samples/OWLModels/example_2-OWL.ecore#/4" />
<uriRef uri="/20" />
</_1:RDFSDataType>
<_1:UniformResourceIdentifier name="eml:rows" uriRef="/19/@uriRef.0" />
<_1:RDFSDataType propertyForRange="/55">
<resource href="/UML2OWL/Samples/OWLModels/example_2-OWL.ecore#/4" />
<uriRef uri="/22" />
</_1:RDFSDataType>
<_1:UniformResourceIdentifier name="eml:columns" uriRef="/21/@uriRef.0" />
<_1:RDFSDataType>
<uriRef uri="/24" />
</_1:RDFSDataType>
<_1:UniformResourceIdentifier name="xsd:boolean" uriRef="/23/@uriRef.0" />
<_1:RDFSDataType propertyForRange="/31 /43">
<uriRef uri="/26" literal="/68 /70 /72 /74 /76 /78 /80 /82 /84 /86 /89 /91" />
</_1:RDFSDataType>
<_1:UniformResourceIdentifier name="xsd:nonNegativeInteger" uriRef="/25/@uriRef.0" />
<_1:RDFSDataType propertyForRange="/34 /37 /40">
<uriRef uri="/28" />
</_1:RDFSDataType>
<_1:UniformResourceIdentifier name="xsd:string" uriRef="/27/@uriRef.0" />
<_1:RDFSDataType>
<uriRef uri="/30" />
</_1:RDFSDataType>
<_1:UniformResourceIdentifier name="xsd:integer" uriRef="/29/@uriRef.0" />
<OWLDatatypeProperty domain="/7" range="/25" propertyRestriction="/67">
<uriRef uri="/33" fragmentIdentifier="/32" />
</OWLDatatypeProperty>
<_1:LocalName name="Ecological_classification.id" uriRef="/31/@uriRef.0" />
<_1:UniformResourceIdentifier name="Ecological_classification.id" uriRef="/31/@uriRef.0" />
<OWLDatatypeProperty domain="/7" range="/27" propertyRestriction="/69">
<uriRef uri="/36" fragmentIdentifier="/35" />
</OWLDatatypeProperty>
<_1:LocalName name="Ecological_classification.name" uriRef="/34/@uriRef.0" />
<_1:UniformResourceIdentifier name="Ecological_classification.name" uriRef="/34/@uriRef.0" />
<OWLDatatypeProperty domain="/7" range="/27" propertyRestriction="/71">
<uriRef uri="/39" fragmentIdentifier="/38" />
</OWLDatatypeProperty>
<_1:LocalName name="Ecological_classification.description" uriRef="/37/@uriRef.0" />
<_1:UniformResourceIdentifier name="Ecological_classification.description"
uriRef="/37/@uriRef.0" />
<OWLDatatypeProperty domain="/7" range="/27" propertyRestriction="/73">
<uriRef uri="/42" fragmentIdentifier="/41" />
</OWLDatatypeProperty>
<_1:LocalName name="Ecological_classification.observations" uriRef="/40/@uriRef.0" />
<_1:UniformResourceIdentifier name="Ecological_classification.observations"
uriRef="/40/@uriRef.0" />
<OWLDatatypeProperty domain="/10" range="/25" propertyRestriction="/75">
<uriRef uri="/45" fragmentIdentifier="/44" />
</OWLDatatypeProperty>
<_1:LocalName name="Grid.id" uriRef="/43/@uriRef.0" />
<_1:UniformResourceIdentifier name="Grid.id" uriRef="/43/@uriRef.0" />
<OWLDatatypeProperty domain="/10" range="/15" propertyRestriction="/77">
<uriRef uri="/48" fragmentIdentifier="/47" />
</OWLDatatypeProperty>
<_1:LocalName name="Grid.cell_size_X" uriRef="/46/@uriRef.0" />
<_1:UniformResourceIdentifier name="Grid.cell_size_X" uriRef="/46/@uriRef.0" />
<OWLDatatypeProperty domain="/10" range="/17" propertyRestriction="/79">
<uriRef uri="/51" fragmentIdentifier="/50" />
</OWLDatatypeProperty>
<_1:LocalName name="Grid.cell_size_Y" uriRef="/49/@uriRef.0" />
<_1:UniformResourceIdentifier name="Grid.cell_size_Y" uriRef="/49/@uriRef.0" />
<OWLDatatypeProperty domain="/10" range="/19" propertyRestriction="/81">
<uriRef uri="/54" fragmentIdentifier="/53" />
</OWLDatatypeProperty>
<_1:LocalName name="Grid.row_size" uriRef="/52/@uriRef.0" />
<_1:UniformResourceIdentifier name="Grid.row_size" uriRef="/52/@uriRef.0" />
<OWLDatatypeProperty domain="/10" range="/21" propertyRestriction="/83">
<uriRef uri="/57" fragmentIdentifier="/56" />
</OWLDatatypeProperty>
<_1:LocalName name="Grid.column_size" uriRef="/55/@uriRef.0" />
<_1:UniformResourceIdentifier name="Grid.column_size" uriRef="/55/@uriRef.0" />
<OWLDatatypeProperty domain="/10" range="/13" propertyRestriction="/85">
<uriRef uri="/60" fragmentIdentifier="/59" />
</OWLDatatypeProperty>
<_1:LocalName name="Grid.georef_utm" uriRef="/58/@uriRef.0" />
<_1:UniformResourceIdentifier name="Grid.georef_utm" uriRef="/58/@uriRef.0" />
<OWLObjectProperty definedResource="/87" domain="/7" range="/10" propertyRestriction="/88"
OWLInverseOf="/64" inverseProperty="/64">
<uriRef uri="/63" fragmentIdentifier="/62" />
</OWLObjectProperty>
<_1:LocalName name="Ecological_classification.has_grid" uriRef="/61/@uriRef.0" />
<_1:UniformResourceIdentifier name="Ecological_classification.has_grid" uriRef="/61/@uriRef.0" />
<InverseFunctionalProperty domain="/10" range="/7" propertyRestriction="/90" OWLInverseOf="/61"
inverseProperty="/61">
<uriRef uri="/66" fragmentIdentifier="/65" />
</InverseFunctionalProperty>
<_1:LocalName name="Grid.has_ecological_classification" uriRef="/64/@uriRef.0" />
<_1:UniformResourceIdentifier name="Grid.has_ecological_classification" uriRef="/64/@uriRef.0" />
<CardinalityRestriction superClass="/7" OWLOnProperty="/31" OWLCardinality="/68" />
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" cardinalityRestriction="/67" />
<CardinalityRestriction superClass="/7" OWLOnProperty="/34" OWLCardinality="/70" />
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" cardinalityRestriction="/69" />
<CardinalityRestriction superClass="/7" OWLOnProperty="/37" OWLCardinality="/72" />
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" cardinalityRestriction="/71" />
<CardinalityRestriction superClass="/7" OWLOnProperty="/40" OWLCardinality="/74" />
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" cardinalityRestriction="/73" />
<CardinalityRestriction superClass="/10" OWLOnProperty="/43" OWLCardinality="/76" />
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" cardinalityRestriction="/75" />
<CardinalityRestriction superClass="/10" OWLOnProperty="/46" OWLCardinality="/78" />
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" cardinalityRestriction="/77" />
<CardinalityRestriction superClass="/10" OWLOnProperty="/49" OWLCardinality="/80" />
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" cardinalityRestriction="/79" />
<CardinalityRestriction superClass="/10" OWLOnProperty="/52" OWLCardinality="/82" />
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" cardinalityRestriction="/81" />
<CardinalityRestriction superClass="/10" OWLOnProperty="/55" OWLCardinality="/84" />
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" cardinalityRestriction="/83" />
<CardinalityRestriction superClass="/10" OWLOnProperty="/58" OWLCardinality="/86" />
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" cardinalityRestriction="/85" />
<FunctionalProperty isDefinedBy="/61" />
<CardinalityRestriction superClass="/7" OWLOnProperty="/61" OWLCardinality="/89" />
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" cardinalityRestriction="/88" />
<MinCardinalityRestriction superClass="/10" OWLOnProperty="/64" OWLMinCardinality="/91" />
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" minCardinalityRestriction="/90" />
</xmi:XMI>
Como podemos ver en la sección 2.3, a partir de este modelo, vamos a ejecutar la transformación OWL2XML para obtener la representación del fichero OWL. A continuación, mostramos las reglas aplicadas; la transformación OWL2XML.atl tiene como entrada el fichero example-OWL.ecore y construye como salida el example.owl.
Graph2Root
Esta regla transforma el elemento "OWLGraph" del modelo OWL en el elemento raíz de uno XML. Además, añade los espacios de nombres predefinidos al archivo OWL.
rule Graph2Root {
from
g : OWL!OWLGraph
to
r : XML!Root (
name <- 'rdf:RDF',
children <- Sequence {
att1, att2, att3, att4, att5, att6,
g.ontology
}
),
att1 : XML!Attribute (name <- 'xmlns:rdf', value <- 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'),
att2 : XML!Attribute (name <- 'xmlns:rdfs', value <- 'http://www.w3.org/2000/01/rdf-schema#'),
att3 : XML!Attribute (name <- 'xmlns:xsd', value <- 'http://www.w3.org/2001/XMLSchema#'),
att4 : XML!Attribute (name <- 'xmlns:owl', value <- 'http://www.w3.org/2002/07/owl#'),
att5 : XML!Attribute (name <- 'xmlns:eml', value <- 'http://www.ual.es/acg/soleres/eml/eml-spatialRaster.xsd'),
att6 : XML!Attribute (name <- 'xmlns', value <- g.ontology->first().getURI() + '#'),
att7 : XML!Attribute (name <- 'xml:base', value <- g.ontology->first().getURI())
}
Código de origen:
<OWLGraph ontology="/4">
<uriRef uri="/2" fragmentIdentifier="/1/@localName.0" namespace="/3" />
</OWLGraph>
<_1:Document xmlBase="/3">
<localName name="ontology" uriRef="/0/@uriRef.0" />
<namespaceDefinition namespacePrefix="ontology" namespace="/3" />
</_1:Document>
<_1:UniformResourceIdentifier name="ontology" uriRef="/0/@uriRef.0" />
<_1:Namespace document="/1" namespaceURIRef="/0/@uriRef.0"
namespaceDefinition="/1/@namespaceDefinition.0" />
Código generado:
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
xmlns:rdfs='http://www.w3.org/2000/01/rdf-schema#'
xmlns:xsd='http://www.w3.org/2001/XMLSchema#'
xmlns:owl='http://www.w3.org/2002/07/owl#'
xmlns:eml='http://www.ual.es/acg/soleres/eml/eml-spatialRaster.xsd'
xmlns='http://www.ual.es/acg/soleres/ontology#'>
Ontology2Element
rule Ontology2Element {
from
o : OWL!OWLOntology
to
e : XML!Element ( name <- 'owl:Ontology', children <- about ),
about : XML!Attribute (
name <- 'rdf:about',
value <- o.uriRef->collect( e | e.fragmentIdentifier.name )->flatten()->first()
)
do {
for ( i in o.OWLImports ) {
thisModule.addImports( o, i );
}
}
}
Código de origen:
<OWLOntology owlUniverse="/7 /10 /13 /15 /17 /19 /21" owlGraph="/0">
<uriRef uri="/6" fragmentIdentifier="/5"/>
</OWLOntology>
<_1:LocalName name="http://www.ual.es/acg/soleres/ontology" uriRef="/4/@uriRef.0"/>
<_1:UniformResourceIdentifier name="http://www.ual.es/acg/soleres/ontology" uriRef="/4/@uriRef.0"/>
Código generado:
<owl:Ontology rdf:about = 'http://www.ual.es/acg/soleres/ontology'/>
Class2Element
rule Class2Element{
from
c : OWL!OWLClass (
c.oclIsTypeOf(OWL!OWLClass)
)
to
e : XML!Element (
name <- 'owl:Class',
children <- Sequence{ID,label},
parent <- OWL!OWLGraph.allInstances()->any( e | e.oclIsTypeOf(OWL!OWLGraph))
),
ID : XML!Attribute ( name <- 'rdf:ID', value <- c.getURI() ),
label : XML!Element ( name <- 'rdfs:label', children <- label_text ),
label_text : XML!Text ( name <- '#text', value <- c.getLabel() )
do {
for (s in c.subClassOf ) {
if (s.oclIsTypeOf(OWL!OWLClass))
thisModule.makeSubClass(c,s);
if (s.oclIsTypeOf(OWL!UnionClass))
thisModule.makeSubClass(c,s);
if (s.oclIsTypeOf(OWL!CardinalityRestriction))
thisModule.makeCardinalityRestrictionSubClass(c,s);
if (s.oclIsTypeOf(OWL!MaxCardinalityRestriction))
thisModule.makeMaxCardinalityRestrictionSubClass(c,s);
if (s.oclIsTypeOf(OWL!MinCardinalityRestriction))
thisModule.makeMinCardinalityRestrictionSubClass(c,s);
}
}
}
Ejemplo de código de origen:
<OWLClass subClassOf="/67 /69 /71 /73 /88" propertyForDomain="/31 /34 /37 /40 /61" propertyForRange="/64" ontology="/4">
<uriRef uri="/9" fragmentIdentifier="/8"/>
<label lexicalForm="Ecological_classification"/>
</OWLClass>
<_1:LocalName name="Ecological_classification" uriRef="/7/@uriRef.0"/>
<_1:UniformResourceIdentifier name="Ecological_classification" uriRef="/7/@uriRef.0"/>
Ejemplo de código generado:
<owl:Class rdf:ID = 'Ecological_classification'>
<rdfs:label>Ecological_classification</rdfs:label>
</owl:Class>
makeCardinalityRestrictionSubClass
rule makeCardinalityRestrictionSubClass( c : OWL!OWLClass, s : OWL!CardinalityRestriction ) {
to
x : XML!Element (
name <- 'rdfs:subClassOf',
children <- e,
parent <- c
),
e : XML!Element ( name <- 'owl:Restriction', children <- Sequence{on, card} ),
on : XML!Element ( name <- 'owl:onProperty', children <- on_attr ),
on_attr : XML!Attribute ( name <- 'rdf:resource', value <- '#' + s.OWLOnProperty.getURI() ),
card : XML!Element ( name <- 'owl:cardinality ', children <- Sequence{card_attr, card_text} ),
card_attr : XML!Attribute ( name <- 'rdf:datatype', value <- s.getDatatypeURI() ),
card_text : XML!Text ( name <- '#text', value <- s.OWLCardinality.lexicalForm )
}
Ejemplo de código de origen:
<CardinalityRestriction superClass="/7" OWLOnProperty="/31" OWLCardinality="/68"/>
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" cardinalityRestriction="/67"/>
Ejemplo de código generado:
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource = '#Ecological_classification.id'/>
<owl:cardinality rdf:datatype = 'xsd:nonNegativeInteger'>1</owl:cardinality >
</owl:Restriction>
</rdfs:subClassOf>
makeMinCardinalityRestrictionSubClass
rule makeMinCardinalityRestrictionSubClass( c : OWL!OWLClass, s : OWL!MinCardinalityRestriction ) {
to
x : XML!Element (
name <- 'rdfs:subClassOf',
children <- e,
parent <- c
),
e : XML!Element (
name <- 'owl:Restriction',
children <- Sequence{on, card}
),
on : XML!Element ( name <- 'owl:onProperty', children <- on_attr ),
on_attr : XML!Attribute ( name <- 'rdf:resource', value <- '#' + s.OWLOnProperty.getURI() ),
card : XML!Element ( name <- 'owl:minCardinality ', children <- Sequence{card_attr, card_text} ),
card_attr : XML!Attribute ( name <- 'rdf:datatype', value <- s.getDatatypeURI() ),
card_text : XML!Text ( name <- '#text', value <- s.OWLMinCardinality.lexicalForm )
}
Ejemplo de código de origen:
<MinCardinalityRestriction superClass="/10" OWLOnProperty="/64" OWLMinCardinality="/91"/>
<_1:TypedLiteral lexicalForm="1" datatypeURI="/25/@uriRef.0" minCardinalityRestriction="/90"/>
Ejemplo de código generado:
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource = '#Grid.has_ecological_classification'/>
<owl:minCardinality rdf:datatype = 'xsd:nonNegativeInteger'>1</owl:minCardinality >
</owl:Restriction>
</rdfs:subClassOf>
DatatypeProperty2Element
rule DatatypeProperty2Element {
from
d : OWL!OWLDatatypeProperty
to
e : XML!Element (
name <- 'owl:DatatypeProperty',
children <- Sequence{ID,domain,range},
parent <- OWL!OWLGraph.allInstances()->any( e | e.oclIsTypeOf(OWL!OWLGraph))
),
ID : XML!Attribute (
name <- 'rdf:ID',
value <- d.getURI()
),
domain : XML!Element (
name <- 'rdfs:domain',
children <- domain_attr
),
domain_attr : XML!Attribute (
name <- 'rdf:resource',
value <- '#' + d.domain->any( c | c.oclIsKindOf(OWL!OWLClass)).getURI()
),
range : XML!Element (
name <- 'rdfs:range',
children <- range_attr
),
range_attr : XML!Attribute (
name <- 'rdf:resource',
value <- d.range->any(c | c.oclIsKindOf(OWL!RDFSDataType)).getURI()
)
}
Ejemplo de código de origen:
<OWLDatatypeProperty domain="/7" range="/25" propertyRestriction="/67">
<uriRef uri="/33" fragmentIdentifier="/32"/>
</OWLDatatypeProperty>
<_1:LocalName name="Ecological_classification.id" uriRef="/31/@uriRef.0"/>
<_1:UniformResourceIdentifier name="Ecological_classification.id" uriRef="/31/@uriRef.0"/>
Ejemplo de código generado:
<owl:DatatypeProperty rdf:ID = 'Ecological_classification.id'>
<rdfs:domain rdf:resource = '#Ecological_classification'/>
<rdfs:range rdf:resource = 'xsd:nonNegativeInteger'/>
</owl:DatatypeProperty>
ObjectProperty2Element
rule ObjectProperty2Element {
from
o : OWL!OWLObjectProperty (
o.oclIsTypeOf(OWL!OWLObjectProperty)
)
to
e : XML!Element (
name <- 'owl:ObjectProperty',
children <- Sequence{ID, domain, range},
parent <- OWL!OWLGraph.allInstances()->any( e | e.oclIsTypeOf(OWL!OWLGraph))
),
ID : XML!Attribute (
name <- 'rdf:ID',
value <- o.getURI()
),
domain : XML!Element (
name <- 'rdfs:domain',
children <- domain_attr
),
domain_attr : XML!Attribute (
name <- 'rdf:resource',
value <- '#' + o.domain->any( c | c.oclIsKindOf(OWL!OWLClass)).getURI()
),
range : XML!Element (
name <- 'rdfs:range',
children <- range_attr
),
range_attr : XML!Attribute (
name <- 'rdf:resource',
value <- '#' + o.range->any( c | c.oclIsKindOf(OWL!OWLClass)).getURI()
)
do {
if (not o.OWLInverseOf.oclIsUndefined())
thisModule.addInverse(o);
for (s in o.subPropertyOf ) {
if (s.oclIsKindOf(OWL!OWLObjectProperty))
thisModule.makeSubProperty(o,s);
}
}
}
(called rule)
rule addInverse( o : OWL!OWLObjectProperty ) {
to
e : XML!Element (
name <- 'owl:inverseOf',
children <- e_attr,
parent <- o
),
e_attr : XML!Attribute (
name <- 'rdf:resource',
value <- '#' + o.OWLInverseOf.getURI()
)
}
Ejemplo de código de origen:
<OWLObjectProperty definedResource="/87" domain="/7" range="/10" propertyRestriction="/88" OWLInverseOf="/64" inverseProperty="/64">
<uriRef uri="/63" fragmentIdentifier="/62"/>
</OWLObjectProperty>
<_1:LocalName name="Ecological_classification.has_grid" uriRef="/61/@uriRef.0"/>
<_1:UniformResourceIdentifier name="Ecological_classification.has_grid" uriRef="/61/@uriRef.0"/>
Ejemplo de código generado:
<owl:ObjectProperty rdf:ID = 'Ecological_classification.has_grid'>
<rdfs:domain rdf:resource = '#Ecological_classification'/>
<rdfs:range rdf:resource = '#Grid'/>
<owl:inverseOf rdf:resource = '#Grid.has_ecological_classification'/>
</owl:ObjectProperty>
InverseFunctionalProperty2Element
rule InverseFunctionalProperty2Element {
from
o : OWL!InverseFunctionalProperty (
o.oclIsTypeOf(OWL!InverseFunctionalProperty)
)
to
e : XML!Element (
name <- 'owl:InverseFunctionalProperty',
children <- Sequence{ID, domain, range},
parent <- OWL!OWLGraph.allInstances()->any( e | e.oclIsTypeOf(OWL!OWLGraph))
),
ID : XML!Attribute (
name <- 'rdf:ID',
value <- o.getURI()
),
domain : XML!Element (
name <- 'rdfs:domain',
children <- domain_attr
),
domain_attr : XML!Attribute (
name <- 'rdf:resource',
value <- '#' + o.domain->any( c | c.oclIsKindOf(OWL!OWLClass)).getURI()
),
range : XML!Element (
name <- 'rdfs:range',
children <- range_attr
),
range_attr : XML!Attribute (
name <- 'rdf:resource',
value <- '#' + o.range->any( c | c.oclIsKindOf(OWL!OWLClass)).getURI()
)
do {
if (not o.OWLInverseOf.oclIsUndefined())
thisModule.addInverse(o);
for (s in o.subPropertyOf ) {
if (s.oclIsKindOf(OWL!OWLObjectProperty))
thisModule.makeSubProperty(o,s);
}
}
}
(called rule)
rule addInverse( o : OWL!OWLObjectProperty ) {
to
e : XML!Element (
name <- 'owl:inverseOf',
children <- e_attr,
parent <- o
),
e_attr : XML!Attribute (
name <- 'rdf:resource',
value <- '#' + o.OWLInverseOf.getURI()
)
}
Ejemplo de código de origen:
<InverseFunctionalProperty domain="/10" range="/7" propertyRestriction="/90" OWLInverseOf="/61" inverseProperty="/61">
<uriRef uri="/66" fragmentIdentifier="/65"/>
</InverseFunctionalProperty>
<_1:LocalName name="Grid.has_ecological_classification" uriRef="/64/@uriRef.0"/>
<_1:UniformResourceIdentifier name="Grid.has_ecological_classification" uriRef="/64/@uriRef.0"/>
Ejemplo de código generado:
<owl:InverseFunctionalProperty rdf:ID = 'Grid.has_ecological_classification'>
<rdfs:domain rdf:resource = '#Grid'/>
<rdfs:range rdf:resource = '#Ecological_classification'/>
<owl:inverseOf rdf:resource = '#Ecological_classification.has_grid'/>
</owl:InverseFunctionalProperty>
FunctionalProperty2Element
rule FunctionalProperty {
from
o : OWL!FunctionalProperty (
o.oclIsTypeOf( OWL!FunctionalProperty )
)
to
e : XML!Element (
name <- 'owl:FunctionalProperty',
children <- a,
parent <- OWL!OWLGraph.allInstances()->any( e | e.oclIsTypeOf(OWL!OWLGraph))
),
a : XML!Attribute (
name <- 'rdf:about',
value <- '#' + o.isDefinedBy->asSequence()->any( e | e.oclIsKindOf(OWL!Property ) ).getURI()
)
}
Ejemplo de código de origen:
<FunctionalProperty isDefinedBy="/61"/>
Ejemplo de código generado:
<owl:FunctionalProperty rdf:about = '#Ecological_classification.has_grid'/>
Resultado del proceso
Una vez ejecutadas todas las reglas del fichero OWL2XML.atl de transformación, obtenemos el modelo XML que es equivalente con el fichero ".owl" que representa la ontología EID final:
<?xml version='1.0' encoding='ISO-8859-1'?>
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'
xmlns:rdfs='http://www.w3.org/2000/01/rdf-schema#' xmlns:xsd='http://www.w3.org/2001/XMLSchema#'
xmlns:owl='http://www.w3.org/2002/07/owl#'
xmlns:eml='http://www.ual.es/acg/soleres/eml/eml-spatialRaster.xsd'
xmlns='http://www.ual.es/acg/soleres/ontology#'>
<owl:Ontology rdf:about='http://www.ual.es/acg/soleres/ontology' />
<owl:Class rdf:ID='Ecological_classification'>
<rdfs:label>Ecological_classification</rdfs:label>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource='#Ecological_classification.id' />
<owl:cardinality rdf:datatype='xsd:nonNegativeInteger'>1</owl:cardinality>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource='#Ecological_classification.name' />
<owl:cardinality rdf:datatype='xsd:nonNegativeInteger'>1</owl:cardinality>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource='#Ecological_classification.description' />
<owl:cardinality rdf:datatype='xsd:nonNegativeInteger'>1</owl:cardinality>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource='#Ecological_classification.observations' />
<owl:cardinality rdf:datatype='xsd:nonNegativeInteger'>1</owl:cardinality>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource='#Ecological_classification.has_grid' />
<owl:cardinality rdf:datatype='xsd:nonNegativeInteger'>1</owl:cardinality>
</owl:Restriction>
</rdfs:subClassOf>
</owl:Class>
<owl:Class rdf:ID='Grid'>
<rdfs:label>Grid</rdfs:label>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource='#Grid.id' />
<owl:cardinality rdf:datatype='xsd:nonNegativeInteger'>1</owl:cardinality>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource='#Grid.cell_size_X' />
<owl:cardinality rdf:datatype='xsd:nonNegativeInteger'>1</owl:cardinality>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource='#Grid.cell_size_Y' />
<owl:cardinality rdf:datatype='xsd:nonNegativeInteger'>1</owl:cardinality>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource='#Grid.row_size' />
<owl:cardinality rdf:datatype='xsd:nonNegativeInteger'>1</owl:cardinality>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource='#Grid.column_size' />
<owl:cardinality rdf:datatype='xsd:nonNegativeInteger'>1</owl:cardinality>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource='#Grid.georef_utm' />
<owl:cardinality rdf:datatype='xsd:nonNegativeInteger'>1</owl:cardinality>
</owl:Restriction>
</rdfs:subClassOf>
<rdfs:subClassOf>
<owl:Restriction>
<owl:onProperty rdf:resource='#Grid.has_ecological_classification' />
<owl:minCardinality rdf:datatype='xsd:nonNegativeInteger'>1</owl:minCardinality>
</owl:Restriction>
</rdfs:subClassOf>
</owl:Class>
<owl:DatatypeProperty rdf:ID='Ecological_classification.id'>
<rdfs:domain rdf:resource='#Ecological_classification' />
<rdfs:range rdf:resource='xsd:nonNegativeInteger' />
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID='Ecological_classification.name'>
<rdfs:domain rdf:resource='#Ecological_classification' />
<rdfs:range rdf:resource='xsd:string' />
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID='Ecological_classification.description'>
<rdfs:domain rdf:resource='#Ecological_classification' />
<rdfs:range rdf:resource='xsd:string' />
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID='Ecological_classification.observations'>
<rdfs:domain rdf:resource='#Ecological_classification' />
<rdfs:range rdf:resource='xsd:string' />
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID='Grid.id'>
<rdfs:domain rdf:resource='#Grid' />
<rdfs:range rdf:resource='xsd:nonNegativeInteger' />
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID='Grid.cell_size_X'>
<rdfs:domain rdf:resource='#Grid' />
<rdfs:range rdf:resource='eml:cellSizeXDirection' />
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID='Grid.cell_size_Y'>
<rdfs:domain rdf:resource='#Grid' />
<rdfs:range rdf:resource='eml:cellSizeYDirection' />
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID='Grid.row_size'>
<rdfs:domain rdf:resource='#Grid' />
<rdfs:range rdf:resource='eml:rows' />
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID='Grid.column_size'>
<rdfs:domain rdf:resource='#Grid' />
<rdfs:range rdf:resource='eml:columns' />
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID='Grid.georef_utm'>
<rdfs:domain rdf:resource='#Grid' />
<rdfs:range rdf:resource='eml:georeferenceInfo' />
</owl:DatatypeProperty>
<owl:ObjectProperty rdf:ID='Ecological_classification.has_grid'>
<rdfs:domain rdf:resource='#Ecological_classification' />
<rdfs:range rdf:resource='#Grid' />
<owl:inverseOf rdf:resource='#Grid.has_ecological_classification' />
</owl:ObjectProperty>
<owl:InverseFunctionalProperty rdf:ID='Grid.has_ecological_classification'>
<rdfs:domain rdf:resource='#Grid' />
<rdfs:range rdf:resource='#Ecological_classification' />
<owl:inverseOf rdf:resource='#Ecological_classification.has_grid' />
</owl:InverseFunctionalProperty>
<owl:FunctionalProperty rdf:about='#Ecological_classification.has_grid' />
</rdf:RDF>