This project is deprecated.
With this library you can take a "nice" XML and generate Pharo class hierarchy with Magritte Descriptions for each variable. I use Magritte XML Bindings, which gives the hierarchy free XML import/export.
The generator will try to guess basic types (Boolean, Integer, Float, String), and the relationship between the parent and child elements (attribute, collection (oneToMany), reference (oneToOne)).
For example if you feed it "nice" XMLs like this one
<machine id="12">
<version value="1.2.7" />
<anyOnline>false</anyOnline>
<nodes>
<node id="node-1">
<isOnline>false</isOnline>
<address>
<host>127.0.0.1</host>
<port>80</port>
</address>
</node>
</nodes>
</machine>
it will exhaust class hierarchy and populate it with the content
Since it is mostly magic, it doesn't always work, for example in the scenarios below. Note that it may fail in a variety of unforeseen circumstances, so feel free to open an issue.
I didn't look much into how namespaces are actually propagated through the document; not just prefixing, but also NS inheriting. With consistent document the names can be easily mapped.
<xmi:element />
<element xml:attr="value" />
Because I use the container
element as variable name to hold child
references.
This is ok:
<root>
<container>
<child />
<child />
</container>
</root>
This is not ok:
<root>
<container>
<child />
<child />
<otherThing />
</container>
</root>
This is much easier for XMI, but for generic XML there's a lot of ambiguity.
Maybe a type override specifying that source
and target
are #REF
ids to /state-machien/states/state
.
<state-machine>
<states>
<state id="10" />
<state id="15" />
</states>
<transitions>
<transition source="10" target="15" />
</transitions>
<state-machine>
Use the generator along those lines:
dom
is an instance of XMLDocument
gen := XOGStructureGenerator new.
"optional attributes, they have their default values"
gen packageName: 'MachineGenerated'.
gen classPrefix: 'XXX'. "to avoid name conflicts"
gen rootClassName: 'MXObject'. "a class from which all the classes will inherit"
"run the generator; this will NOT create the code yet"
gen processDocument: dom.
"retrieve CBChangesSet¹, so additional modifications can be performed"
changes := gen changes.
(CBChangesBrowser changes: changes refactoringChanges) open.
¹ Documentation on CBChangesSet is available in Changes Builder project
NOTE that all the generated classes must contain this method:
descriptionContainer
<magritteContainer>
^ super descriptionContainer
xmlElementName: self class xmlElementName;
yourself
you can either:
- use
'MXObject'
which implements it - add the method to your own root class
- use
TMXDescription
trait - do whatever you want
obj := XXXClassForRootElement new magritteDescription fromXmlNode: dom root.
obj magritteDescription toXmlDocument: obj.
The inferencers guess the element/attribute value type (String, Boolean, ...) as well as their type that relates them to their attributes and children (list, complex, inlined, ...).
types := XOGTypeClassification new classificationFor: dom.
valueTypes := XOGValueTypeInference new inferDocument: dom.
classification := XOGElementClassification new classifyTypes: types andValues: valueTypes.
Metacello new
baseline: #XMLMAGenerator;
repository: 'github://peteruhnak/xml-magritte-generator/repository';
load
Dependencies:
BaselineOfXMLMAGenerator project latestVersion projects asArray collect: #name. "#('XMLParser' 'XPath' 'Magritte' 'MagritteXMLBindings' 'ChangesBuilder')"