# XML Read/Write

## Overview

`HUtilityXMLParser` and `HUtilityXMLGenerator` are two classes that read/write generic XML data. Currently, XML is used as part of the HSF specification to describe extensions to the format (e.g. the behavior extension) and we encourage its usage for any kind of user data.Various validating and non-validating XML parsers already exist. However, we felt that integrating a simple parser into MVO would simplify the usage of XML and not force people to add another library to their project and possibly deal with the associated licensing issues.

## Parsing XML Data

The `HUtilityXMLParser` class implements a simple non-validating XML parser. It uses a callback architecture to register functions that handle specific tags and these functions in turn query the parsing toolkit for their parameters.First a new instance of HUtilityXMLParser needs to be created. After that a memory buffer containing the XML data in ASCII format must be passed to the toolkit. This buffer must be a valid block containing any number of XML tags.

> HUtilityXMLParser xp; xp.SetupParseBuffer(buffer);

For every XML tag that requires handling a callback function needs to be set. This function receives the tag-name and all the tag parameters. Tags for which no function has been registered will be disregarded. `SetTagCallback` takes the name of the tag, a function pointer and a void pointer to generic data:

    xp.SetTagCallback("BehaviorManager", HBhvBehaviorManager::XMLCallback, model);
    xp.SetTagCallback("Animdef", HBhvBehaviorManager::XMLCallback, model);
    xp.SetTagCallback("Sensor", HBhvSensor::XMLCallback, model);
    ...

Finally, `ProcessXMLData()` must be called to initiate the parsing process:

    xp.ProcessXMLData();

Here is an example of a callback function for the animation sensor tag:

    // the first parameter is a pointer to the XML parser
    // the second parameter indicates if the callback has been called from an "open tag" or from
    // a "close tag". For every tag the callback gets called two times. Once to indicate the start
    // of the tag and once to indicate the end of the tag
    // the third tag is a pointer to extra-data which has been passed in when the callback got registered
    void *HBhvSensor::XMLCallback(HUtilityXMLTag *xt, bool open, void *m_pExtraData)
    {
    char Name[256];
    int active = true;

    HBaseModel *model = (HBaseModel *)m_pExtraData;

    if (open)
    {
            // GetProperty retrieves a tag-property
            // there are various overloaded versions of GetProperty for retrieving string and numerical properties
            // it is the responsibility of the callback to set a default if the property has not been explicitly set
            if (!xt->GetProperty("Name", Name))
                    strcpy(Name, "");

            xt->GetProperty("Active", active);

            HBhvSensor * sensor = new HBhvSensor(Name, active != 0, model->GetBhvBehaviorManager());
            model->GetBhvBehaviorManager()->AddSensor(sensor);

            // the returned void pointer will be added to the stack and can be retrieved by enclosed tag callbacks
            // by calling the function GetStackData()
            // Example:  HBhvSensor * sensor = (HBhvSensor *)xt->GetXMLParser()->GetStackData();
            return (sensor);
    }

    return 0;
    }

## Writing XML Data

`HUtilityXMLGenerator` allows the creation of valid XML blocks. Similar to `HUtilityXMLParser` we start by creating a new `HUtilityXMLGenerator` object. Then each object needs to serialize itself in a hierachical fashion which mirrors the structure of the XML data that needs to be generated:

    HUtilityXMLGenerator xmlgen;
    Serialize(&xmlgen);

After all XML Data has been created `HUtilityXMLGenerator::Finalize` needs to be called and the buffer can be written to a file:

    xmlgen.Finalize();
    FILE *fp;
    fp = fopen(filename, "w");
    fwrite(xmlgen.GetBuffer(), 1, xmlgen.GetBufferSize(), fp);
    fclose(fp);

Here is an example of how a serialization function might look like:

    void HBhvSensor::Serialize(HUtilityXMLGenerator *xmlgen)
    {
    // HUtilityXMLTag represents an XML tag and it's properties
    HUtilityXMLTag xmlt;

    //the tagname needs to be specified
    xmlt.SetTagname("Sensor");

    // Properties are added in a sequential fashion
    // AddProperty takes the property name, the value and for strings an additional parameter indicating
    // if brackets should be placed around the property
    xmlt.AddProperty("Name", m_Name, true);
    xmlt.AddPropertyInt("Active", (int)m_bDefaultActive);

    // To add data (which resides between the start and end-tag) the following function can be used
    // xmlgen->AddListItem(text);

    // if true is passed into SetOpen this indicates that this tag has further subtags
    xmlt.SetOpen(true);

    // after all properties have been set the new tag object is added to the xml generator object
    xmlgen->AddTag(&xmlt);

    // if this tag contains subtags those need to be recursively serialized
    START_LIST_ITERATION(HBhvCondition, m_ConditionList)
            temp->Serialize(xmlgen);
    END_LIST_ITERATION(m_ConditionList);

    START_LIST_ITERATION(HBhvAction, m_ActionList)
            temp->Serialize(xmlgen);
    END_LIST_ITERATION(m_ActionList);

    // Finally the tag needs to be closed
    xmlgen->CloseTag(&xmlt);
    }

Conversation saved
HOOPSY BETA

### Hello! I'm HOOPSY

Your multilingual generative AI assistant for documentation. Ask me anything about HOOPS Visualize 3DF in your own language, or choose a sample question below to start a conversation:

What is HOOPS Visualize 3DF?
What are the latest release notes for HOOPS Visualize 3DF?
How do I start evaluating HOOPS Visualize 3DF?
How do I write my first sample application?
How can I get assistance?

HOOPSY may store conversations according to OpenAI's policy. Responses may not always be accurate.

HOOPSY is thinking...