Skip to content

Simple DOM No XML Editor Programming Discussion

Gary edited this page Mar 10, 2015 · 2 revisions

Table of Contents

The ATF Simple DOM No XML Editor Sample is almost exactly the same as the ATF Simple DOM Editor Sample, except for a few things:

  • It doesn't offer DomNode searching.
  • It doesn't use an XML Schema for its data model.
  • It doesn't persist application data in XML.
Other than this, the samples have exactly the same kind of data: sequences of events with the same attributes, including resources. When running, the applications look alike.

The key difference is not using XML, so this sample demonstrates two things different from SimpleDOMEditor:

  • Defining data types without an XML schema.
  • Saving and reading document data from a non-XML file.
Note that these are quite different things: using an XML Schema does not require saving application data to XML, nor vice versa. Using an XML Schema does make it easier to persist data in XML, however.

It's also worth noting that even though this sample does not use an XML Schema, it still uses the ATF DOM: DOM adapters, for instance. The ATF DOM does not require using an XML Schema.

Other than these differences, both samples' source is very similar, some files being nearly identical. To explore capabilities like using documents, DOM adapters, contexts, a palette, or editing data — common to these two samples — see Simple DOM Editor Programming Discussion.

Programming Overview

Instead of an XML Schema, this sample's DomTypes class defines its types. Its data model is exactly the same as ATF Simple DOM Editor Sample, so it defines the same data types using its own metadata classes, and DomTypes somewhat resembles the Schema class in SimpleDOMEditor. SimpleDOMNoXMLEditor uses the same DOM adapters as the SimpleDOMEditor sample, and they are defined in almost the same way in DomTypes's constructor. The DomTypes constructor also calls NamedMetadata.SetTag() to add information to the type metadata objects for palette types and property descriptors.

SimpleDOMNoXMLEditor uses a simple format to store application data in a text file. Its EventSequenceDocument class contains methods to read and write these text files, which parse and format strings. The Editor class reads and saves event sequence documents using these read and write methods.

Defining Data Model Without an XML Schema

This sample defines a data model without an XML Schema, doing all the work that other samples' schema files, and Schema and SchemaLoader classes do.

Type Definitions

If you use an XML Schema, you define your data model's types in the XML Schema Definition (XSD) language. You can then use the ATF utility DomGen to create a Schema class that defines metadata classes for all the types. Without this facility, you have to create all these type definitions some other way.

Although this sample does not use an XML Schema, it does use the ATF DOM and defines metadata classes for all its types and attributes — very similarly to how it is done in the Schema class in the SimpleDOMEditor sample. And both applications deal with exactly the same event sequence data, so their data model is the same, even though it's realized differently.

Consider how to define the "Event" type. It has the attributes "Name", "Time", and "Duration", and can have any number of "Resource" type children.

SimpleDOMNoXMLEditor creates a DomTypes class for all its type definitions. Here's its definition of the "Event" type, starting with a comment containing the XML Schema definition of the type from the SimpleDOMEditor sample's XML Schema:

//Schema equivalent:
//<!--Event, with name, start time, duration and a list of resources-->
//<xs:complexType name ="eventType">
//  <xs:sequence>
//    <xs:element name="resource" type="resourceType" maxOccurs="unbounded"/>
//  </xs:sequence>
//  <xs:attribute name="name" type="xs:string"/>
//  <xs:attribute name="time" type="xs:integer"/>
//  <xs:attribute name="duration" type="xs:integer"/>
//</xs:complexType>
/// <summary>
/// Event type</summary>
public static class eventType
{
    static eventType()
    {
        Type.Define(nameAttribute);
        Type.Define(timeAttribute);
        Type.Define(durationAttribute);
        Type.Define(resourceChild);
        resourceChild.AddRule(new ChildCountRule(1, int.MaxValue));
    }

    public readonly static DomNodeType Type = new DomNodeType("eventType");
    public readonly static AttributeInfo nameAttribute =
        new AttributeInfo("name", new AttributeType(AttributeTypes.String.ToString(), typeof(string)));
    public readonly static AttributeInfo timeAttribute =
        new AttributeInfo("time", new AttributeType(AttributeTypes.Int32.ToString(), typeof(int)));
    public readonly static AttributeInfo durationAttribute =
        new AttributeInfo("duration", new AttributeType(AttributeTypes.Int32.ToString(), typeof(int)));
    public readonly static ChildInfo resourceChild = new ChildInfo("resource", Type, true);
}

The initial calls to DomNodeType.Define(), like Type.Define(nameAttribute), create attributes for the type, which the XML Schema definition also does.

The attribute metadata class members, such as nameAttribute, are explicitly constructed:

public readonly static AttributeInfo nameAttribute =
    new AttributeInfo("name", new AttributeType(AttributeTypes.String.ToString(), typeof(string)));

The constructor for AttributeInfo here is

public AttributeInfo(string name, AttributeType type)

and the constructor for AttributeType used there is

public AttributeType(string name, Type type)

AttributeTypes is an enumeration for an attribute's primitive types.

This assignment for nameAttribute above spells out that the "Event" type's "name" attribute is a string, just as the XML Schema definition specified.

Similarly, the "Resource" type children of this type are specified in the ChildInfo constructor:

public readonly static ChildInfo resourceChild = new ChildInfo("resource", Type, true);

As the constructor for ChildInfo indicates, the event's resources are in a list of DomNodes:

public ChildInfo(string name, DomNodeType type, bool isList)

Here's the corresponding class for the "Event" type from the SimpleDOMEditor sample's Schema file:

public static class eventType
{
    public static DomNodeType Type;
    public static AttributeInfo nameAttribute;
    public static AttributeInfo timeAttribute;
    public static AttributeInfo durationAttribute;
    public static ChildInfo resourceChild;
}

The eventType classes in the two samples have exactly the same fields of the same metadata types: both have a Type member that's a DomNodeType, and so forth.

Here's how the class for events is initialized in Schema.Initialize() in SimpleDOMEditor:

eventType.Type = typeCollection.GetNodeType("eventType");
eventType.nameAttribute = eventType.Type.GetAttributeInfo("name");
eventType.timeAttribute = eventType.Type.GetAttributeInfo("time");
eventType.durationAttribute = eventType.Type.GetAttributeInfo("duration");
eventType.resourceChild = eventType.Type.GetChildInfo("resource");

The fields also end up being initialized to the same values. For instance, this line in DomTyes

public readonly static DomNodeType Type = new DomNodeType("eventType");

produces the same result as this one in Schema:

eventType.Type = typeCollection.GetNodeType("eventType");

Restrictions on types must also be handled. For example, the eventType definition in DomTyes above added a rule to the resourceChild's ChildInfo:

resourceChild.AddRule(new ChildCountRule(1, int.MaxValue));

This rule's constructor specifies the minimum and maximum child count:

public ChildCountRule(int min, int max)

Defining DOM Adapters

SimpleDOMNoXMLEditor uses the same DOM adapters as the SimpleDOMEditor sample, and they are defined in almost the same way. In SimpleDOMEditor, DOM adapters are defined in SchemaLoader; in SimpleDOMNoXMLEditor, they are defined in DomTypes's constructor:

static DomTypes()
{
    // register extensions
    eventSequenceType.Type.Define(new ExtensionInfo<EventSequenceDocument>());
    eventSequenceType.Type.Define(new ExtensionInfo<EventSequenceContext>());
    eventSequenceType.Type.Define(new ExtensionInfo<MultipleHistoryContext>());
    eventSequenceType.Type.Define(new ExtensionInfo<EventSequence>());
    eventSequenceType.Type.Define(new ExtensionInfo<ReferenceValidator>());
    eventSequenceType.Type.Define(new ExtensionInfo<UniqueIdValidator>());
    eventSequenceType.Type.Define(new ExtensionInfo<DomNodeQueryable>());

    eventType.Type.Define(new ExtensionInfo<Event>());
    eventType.Type.Define(new ExtensionInfo<EventContext>());

    resourceType.Type.Define(new ExtensionInfo<Resource>());

    // Enable metadata driven property editing for events and resources
    AdapterCreator<CustomTypeDescriptorNodeAdapter> creator =
        new AdapterCreator<CustomTypeDescriptorNodeAdapter>();
    eventType.Type.AddAdapterCreator(creator);
    resourceType.Type.AddAdapterCreator(creator);

The only difference between these definitions and the ones in SchemaLoader are the type names, since these types are defined in DomTypes rather than Schema.

An AdapterCreator is used here just as in SimpleDOMEditor for the same reason: to make the property editors conform to the data in the property descriptors, defined next.

Adding Type Metadata Information

The DomTypes constructor carries out another task that the SchemaLoader in SimpleDOMEditor did: calling NamedMetadata.SetTag() to add information to the type metadata objects. This information is used later for palette types and property descriptors.

This sample adds the same kind of information that SimpleDOMEditor did. First, for palette types:

eventType.Type.SetTag(
    new NodeTypePaletteItem(
        eventType.Type,
        Localizer.Localize("Event"),
        Localizer.Localize("Event in a sequence"),
        Resources.EventImage));

The other use for the tag information is for property descriptors. These are used by property editors to determine which attributes, that is, properties, appear in the property editors for each type.

eventType.Type.SetTag(
    new PropertyDescriptorCollection(
        new Sce.Atf.Dom.PropertyDescriptor[] {
                new AttributePropertyDescriptor(
                    Localizer.Localize("Name"),
                    eventType.nameAttribute,
                    null,
                    Localizer.Localize("Event name"),
                    false),
        ...

Again, these statements are almost identical to the equivalent ones in SchemaLoader; only the type names differ.

Persisting Data

SimpleDOMNoXMLEditor uses a very simple format to store application data in a text file with the extension .SimpleDomTxt. Consider the following data, with two events, as displayed in the application:

This is the corresponding data in the saved file:

{source} eventSequence event name="Event1", time=5, duration=5 resource type="animationResourceType", name="Animation1", compressed=true resource type="geometryResourceType", name="Geometry1" event name="Event2", time=7, duration=4 resource type="animationResourceType", name="Animation" resource type="geometryResourceType", name="Geometry" {source}

The file's first line shows that it's a file with event sequences. Each event is listed on one line with its name and any other attributes, followed by its resources and their attributes, one line per resource.

EventSequenceDocument Class Read and Write Methods

The EventSequenceDocument class contains methods to read and write .SimpleDomTxt files:

  • Read(): Read the .SimpleDomTxt file from a Stream, creating an EventSequenceDocument, which is the adapted root of a DomNode tree.
  • Write(): Write an EventSequenceDocument to a Stream.
These methods perform a similar function to the DomXmlReader.Read() and DomXmlWriter.Write() methods, which read and write application data from and to a DomNode tree. The EventSequenceDocument read and write methods mainly handle text, converting strings back and forth that embody the information in the tree's DomNodes. For instance, here's Write():
public static void Write(EventSequenceDocument document, Stream stream)
{
    using (StreamWriter writer = new StreamWriter(stream))
    {
        writer.WriteLine("eventSequence");

        DomNode root = document.DomNode;
        foreach (DomNode eventNode in root.GetChildren(DomTypes.eventSequenceType.eventChild))
            WriteEvent(eventNode, writer);
    }
}

The method gets the root DomNode from the document and iterates through all its children. It writes all the event data for each child event with WriteEvent():

private static void WriteEvent(DomNode eventNode, StreamWriter writer)
{
    StringBuilder lineBuilder = new StringBuilder(
        "event name=\"" + eventNode.GetAttribute(DomTypes.eventType.nameAttribute) + "\"");
    WriteAttribute(eventNode, "time", lineBuilder);
    WriteAttribute(eventNode, "duration", lineBuilder);
    writer.WriteLine(lineBuilder.ToString());

    foreach (DomNode resourceNode in eventNode.GetChildren(DomTypes.eventType.resourceChild))
        WriteResource(resourceNode, writer);
}

WriteEvent() uses a StringBuilder to format text for each event, writing a line for the event itself plus all its attributes that it obtains with DomNode.GetAttribute(). After that, it gets all the child attributes for the resources and writes a line for each one with WriteResource(). WriteResource() operates similarly to WriteEvent(), obtaining all the "Resource" type attributes and formatting them for output.

The EventSequenceDocument.Read() method functions similarly, reading the .SimpleDomTxt file, parsing its data, and creating DomNodes with the right attributes.

Editor Class Open and Save Methods

The Editor class for both the SimpleDOMEditor and SimpleDOMNoXMLEditor samples create and save event sequence documents in practically the same way.

The Open() method of SimpleDOMEditor reads application data from a stream this way:

DomXmlReader reader = new DomXmlReader(m_schemaLoader);
node = reader.Read(stream, uri);

and SimpleDOMNoXMLEditor does this:

node = EventSequenceDocument.Read(stream).DomNode;

Similarly, for saving a document in the Save() method, here's SimpleDOMEditor's way:

DomXmlWriter writer = new DomXmlWriter(m_schemaLoader.TypeCollection);
EventSequenceDocument eventSequenceDocument = (EventSequenceDocument)document;
writer.Write(eventSequenceDocument.DomNode, stream, uri);

and SimpleDOMNoXMLEditor:

EventSequenceDocument eventSequenceDocument = (EventSequenceDocument)document;
EventSequenceDocument.Write(eventSequenceDocument, stream);

Topics in this section

Clone this wiki locally