NMFCode / NMF

This repository contains the entire code for the .NET Modeling Framework
BSD 3-Clause "New" or "Revised" License
36 stars 15 forks source link

Deserialization of ecore with inner text #30

Closed ChrisH07 closed 6 years ago

ChrisH07 commented 6 years ago

Ecore models generated from XML schema files can contain "dummy" attributes to catch inner text of elements. NMF does not currently support reading element inner text. For example, Simulink models have "P" elements with inner text:

<Model>
    <P Name="MdlSubVersion">7</P>
    <P Name="SavedCharacterEncoding">windows-1252</P>
    ...
</Model>

Where the derived schema is:

<xs:element name="P">
  <xs:complexType>
    <xs:simpleContent>
      <xs:extension base="xs:string">   <!-- This element has inner text of type string -->
        <xs:attribute type="xs:string" name="Name"/>
      </xs:extension>
    </xs:simpleContent>
  </xs:complexType>
</xs:element>

Which, according to this, generates the following Ecore model where the value attribute is used to collect the inner text:

<eClassifiers xsi:type="ecore:EClass" name="PType">
  <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
    <details key="name" value="P_._type"/>
    <details key="kind" value="simple"/>
  </eAnnotations>
  <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString">  <!-- This is the inner text attribute -->
    <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
      <details key="name" value=":0"/>      <!-- Docs imply name->:0 with kind->simple denotes this attribute is the inner text -->
      <details key="kind" value="simple"/>
    </eAnnotations>
  </eStructuralFeatures>
  <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString">
    <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
      <details key="kind" value="attribute"/>
      <details key="name" value="Name"/>
      <details key="namespace" value="##targetNamespace"/>
    </eAnnotations>
  </eStructuralFeatures>
</eClassifiers>

I can catch the inner text as XmlNodeType.Text in XmiSerializer.InitializeElementProperties, but it is not clear how I would extend/modify IPropertySerializationInfo to support this behavior or if this is even the appropriate place to handle this case. Any guidance is appreciated. Thank you, Chris

georghinkel commented 6 years ago

I drafted an implementation just now, feel free to test whether it works for that scenario.

ChrisH07 commented 6 years ago

Hi Georg,

Thanks for working on this. Initial testing did not work for my test case. After regenerating classes and NMF model from the ecore model, I hit the exception you added in XmiSerializer. I get the same results when I add the attribute to the nmf model and regenerate code. Interestingly, the new SerializationInfo attributes don't get added to the serialized nmf xml. I'm debugging these issues now and I'll get back to you when I learn more.

Thank you,

Chris

georghinkel commented 6 years ago

I can reproduce the problem that the extension is not serialized - this is a clear bug. However, I was actually able load the XML fragment


<Model>
    <P Name="MdlSubVersion">7</P>
    <P Name="SavedCharacterEncoding">windows-1252</P>
</Model>

using this metamodel (and generated code using the latest NuGet package):


<?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="Test" nsURI=""
    nsPrefix="">
  <eClassifiers xsi:type="ecore:EClass" name="PType">
    <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
      <details key="name" value="P_._type"/>
      <details key="kind" value="simple"/>
    </eAnnotations>
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="value" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString">  <!-- This is the inner text attribute -->
      <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
        <details key="name" value=":0"/>      <!-- Docs imply name->:0 with kind->simple denotes this attribute is the inner text -->
        <details key="kind" value="simple"/>
      </eAnnotations>
    </eStructuralFeatures>
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="name" eType="ecore:EDataType http://www.eclipse.org/emf/2002/Ecore#//EString">
      <eAnnotations source="http:///org/eclipse/emf/ecore/util/ExtendedMetaData">
        <details key="kind" value="attribute"/>
        <details key="name" value="Name"/>
        <details key="namespace" value="##targetNamespace"/>
      </eAnnotations>
    </eStructuralFeatures>
  </eClassifiers>
  <eClassifiers xsi:type="ecore:EClass" name="Model">
    <eStructuralFeatures xsi:type="ecore:EAttribute" name="P" eType="ecore:EClass #//PType" containment="true" upperBound="-1" />
  </eClassifiers>
</ecore:EPackage>

This is exactly the fragment you posted slightly extended with a "Model" class, though the code generator currently has a problem with the name "Model", so you have to manually adjust one type reference in the generated code.

ChrisH07 commented 6 years ago

Looks like my code didn't regenerate correctly. Deleting the code fixed everything. I can now correctly deserialize the inner text. Looks like you already added a test for the transform, so we can close this and handle the serialization separately.

Thanks again for all the help!

Chris