Skip to content
JPVenson edited this page Aug 1, 2022 · 17 revisions

Morestachios Parser creates an Document-Tree for your Template. It can be serialized and can be reused so you only have to parse a Template once. The Document-Tree is stored inside the Document Property of the MorestachioDocumentInfo you obtain by calling Parser.ParseWithOptions(ParserOptionsBuilder.New()....Build()).Document or via the extension method ParserOptionsBuilder.New()....BuildAndParse().Document.

Xml

For an template of I am <Text> {{Data.data.test().next(arg).(last)}} Morestachio will generate an XML that looks like this:

Example Xml

<?xml version="1.0" encoding="utf-8"?>
<MorestachioDocument Location="-1:-1:-1|-1:-1:-1" BlockLocation="0:0:0|0:0:0" MorestachioVersion="5.0.1.631">
  <Children>
    <ContentDocumentItem Location="0:0:0|11:0:11" BlockLocation="0:0:0|0:0:0">
      <Value xml:space="preserve">I am &lt;Text&gt; </Value>
    </ContentDocumentItem>
    <PathDocumentItem Location="12:0:12|48:0:48" EscapeValue="True">
      <ExpressionMultiPart EndsWithDelimiter="False" Location="12:0:12|26:0:26">
        <Expression Location="12:0:12|26:0:26">
          <Path>
            <DataPath>Data</DataPath>
            <DataPath>data</DataPath>
          </Path>
          <Format FormatterName="test" />
        </Expression>
        <Expression Location="28:0:28|33:0:33">
          <Format FormatterName="next">
            <Argument Location="34:0:34|37:0:37">
              <Expression Location="34:0:34|37:0:37">
                <Path>
                  <DataPath>arg</DataPath>
                </Path>
              </Expression>
            </Argument>
          </Format>
        </Expression>
        <Expression Location="38:0:38|39:0:39">
          <Path>
            <SelfAssignment />
          </Path>
          <Format FormatterName="">
            <Argument Location="40:0:40|44:0:44">
              <Expression Location="40:0:40|44:0:44">
                <Path>
                  <DataPath>last</DataPath>
                </Path>
              </Expression>
            </Argument>
          </Format>
        </Expression>
      </ExpressionMultiPart>
    </PathDocumentItem>
  </Children>
</MorestachioDocument>

Code:

public XmlSerializer XmlSerializer { get; }

public DocumentTreeFixture()
{
	XmlSerializer = new XmlSerializer(typeof(MorestachioDocument));
}

public string SerializeXmlToText(object obj)
{
	using (var ms = new MemoryStream())
	{
		XmlSerializer.Serialize(ms, obj);
		return Encoding.UTF8.GetString(ms.ToArray());
	}
}

public IDocumentItem DeSerializeXmlToText(string xmltext)
{
	using (var ms = new MemoryStream(Encoding.UTF8.GetBytes(xmltext)))
	{
		return XmlSerializer.Deserialize(ms) as IDocumentItem;
	}
}

[Test]
public void TestDocumentIsXmlSerilizable()
{
	var template = "I am <Text> {{Data.data('test')}}";
	var morestachioDocumentInfo = ParserOptionsBuilder.New().WithTemplate(template).BuildAndParse();
	var text = SerializeXmlToText(morestachioDocumentInfo.Document);
	var deserialized = DeSerializeXmlToText(text);
}

Json

For the Json Serialization but also for Binary serialization all DocumentItems rely on the ISerializable interface. That has the great benefit of reduced code as there is no duplicated code for serialization to Json and Binary but with that benefit comes also a drawback for JSON. As normal JSON structure is typeless and we are serializing lists of IDocumentItem we have to add the expected type to it. The BinaryFormatter that can be used for binary serializing, does this automatically but not Json.Net. When using Json.Net you must set the TypeNameHandling option of your JsonSerializerSettings to TypeNameHandling.Objects.

Example Json

{
  "$type": "Morestachio.Document.Items.MorestachioDocument",
  "Location": {
    "RangeStart": {
      "Index": -1,
      "Row": -1,
      "Column": -1
    },
    "RangeEnd": {
      "Index": -1,
      "Row": -1,
      "Column": -1
    }
  },
  "MorestachioVersion": "5.0.1.631",
  "BlockLocation": {
    "RangeStart": {
      "Index": 0,
      "Row": 0,
      "Column": 0
    },
    "RangeEnd": {
      "Index": 0,
      "Row": 0,
      "Column": 0
    }
  },
  "Children": [
    {
      "$type": "Morestachio.Document.Items.ContentDocumentItem",
      "Location": {
        "RangeStart": {
          "Index": 0,
          "Row": 0,
          "Column": 0
        },
        "RangeEnd": {
          "Index": 11,
          "Row": 0,
          "Column": 11
        }
      },
      "BlockLocation": {
        "RangeStart": {
          "Index": 0,
          "Row": 0,
          "Column": 0
        },
        "RangeEnd": {
          "Index": 0,
          "Row": 0,
          "Column": 0
        }
      },
      "Children": [],
      "Value": "I am <Text> "
    },
    {
      "$type": "Morestachio.Document.Items.PathDocumentItem",
      "Location": {
        "RangeStart": {
          "Index": 12,
          "Row": 0,
          "Column": 12
        },
        "RangeEnd": {
          "Index": 48,
          "Row": 0,
          "Column": 48
        }
      },
      "MorestachioExpression": {
        "$type": "ExpressionMultiPart",
        "Location": {
          "RangeStart": {
            "Index": 12,
            "Row": 0,
            "Column": 12
          },
          "RangeEnd": {
            "Index": 26,
            "Row": 0,
            "Column": 26
          }
        },
        "Expressions": [
          {
            "$type": "Expression",
            "PathParts": [
              {
                "Key": "Data",
                "Value": 0
              },
              {
                "Key": "data",
                "Value": 0
              }
            ],
            "Formats": [],
            "FormatterName": "test",
            "Location": {
              "RangeStart": {
                "Index": 12,
                "Row": 0,
                "Column": 12
              },
              "RangeEnd": {
                "Index": 26,
                "Row": 0,
                "Column": 26
              }
            },
            "EndsWithDelimiter": false
          },
          {
            "$type": "Expression",
            "PathParts": [],
            "Formats": [
              {
                "$type": "ExpressionArgument",
                "Location": {
                  "RangeStart": {
                    "Index": 34,
                    "Row": 0,
                    "Column": 34
                  },
                  "RangeEnd": {
                    "Index": 37,
                    "Row": 0,
                    "Column": 37
                  }
                },
                "MorestachioExpression": {
                  "$type": "Expression",
                  "PathParts": [
                    {
                      "Key": "arg",
                      "Value": 0
                    }
                  ],
                  "Formats": [],
                  "Location": {
                    "RangeStart": {
                      "Index": 34,
                      "Row": 0,
                      "Column": 34
                    },
                    "RangeEnd": {
                      "Index": 37,
                      "Row": 0,
                      "Column": 37
                    }
                  },
                  "EndsWithDelimiter": false
                }
              }
            ],
            "FormatterName": "next",
            "Location": {
              "RangeStart": {
                "Index": 28,
                "Row": 0,
                "Column": 28
              },
              "RangeEnd": {
                "Index": 33,
                "Row": 0,
                "Column": 33
              }
            },
            "EndsWithDelimiter": false
          },
          {
            "$type": "Expression",
            "PathParts": [
              {
                "Key": null,
                "Value": 3
              }
            ],
            "Formats": [
              {
                "$type": "ExpressionArgument",
                "Location": {
                  "RangeStart": {
                    "Index": 40,
                    "Row": 0,
                    "Column": 40
                  },
                  "RangeEnd": {
                    "Index": 44,
                    "Row": 0,
                    "Column": 44
                  }
                },
                "MorestachioExpression": {
                  "$type": "Expression",
                  "PathParts": [
                    {
                      "Key": "last",
                      "Value": 0
                    }
                  ],
                  "Formats": [],
                  "Location": {
                    "RangeStart": {
                      "Index": 40,
                      "Row": 0,
                      "Column": 40
                    },
                    "RangeEnd": {
                      "Index": 44,
                      "Row": 0,
                      "Column": 44
                    }
                  },
                  "EndsWithDelimiter": false
                }
              }
            ],
            "FormatterName": "",
            "Location": {
              "RangeStart": {
                "Index": 38,
                "Row": 0,
                "Column": 38
              },
              "RangeEnd": {
                "Index": 39,
                "Row": 0,
                "Column": 39
              }
            },
            "EndsWithDelimiter": false
          }
        ],
        "EndsWithDelimiter": false
      },
      "EscapeValue": true
    }
  ]
}

Example Code Json (Note the Formatting option is only for the sake of readability)

It is important to use the AddMorestachioSerializationExtensions from ether Morestachio.Newtonsoft.Json or Morestachio.System.Text.Json nuget package when deserialising the document tree as there are important converters that know how to serialise/deserialise the Morestachio document tree.

public DocumentSerializerJsonNetStrategy()
{
	jsonSerializerSettings = new JsonSerializerSettings()
            .AddMorestachioSerializationExtensions(); //this step is important, if skipped only the first document item will be serialized
	jsonSerializerSettings.Formatting = Formatting.Indented;
}

JsonSerializerSettings jsonSerializerSettings;

public string SerializeToText(IDocumentItem obj)
{
	return JsonConvert.SerializeObject(obj, jsonSerializerSettings);
}

public IDocumentItem DeSerializeToText(string text)
{
	return JsonConvert.DeserializeObject<MorestachioDocument>(text, jsonSerializerSettings);
}