Cody_T
Cody_T

Reputation: 81

Putting c# inside xml

I am using WinForms. I have an XML document that looks like this:

<?xml version="1.0" encoding="utf-8" ?>
<MarcusXMLFile xmlns:Responses="http://www.rewardstrike.com/XMLFile1.xml">
  <response>
    <greatmood>
      <yes>
        <replytocommand>
          <answer>Yes.</answer>
          <answer>Yes, sir.</answer>
          <answer>Settings.Default.User</answer>
        </replytocommand>
      </yes>
    </greatmood>
  </response>
</MarcusXMLFile>

To read this xml document, I use:

private void Responses()
    {
        string query = String.Format("http://www.rewardstrike.com/XMLFile1.xml");
        XmlDocument Responses = new XmlDocument();
        Responses.Load(query);

        XmlNode channel = Responses.SelectSingleNode("MarcusXMLFile");



        if (QEvent == "yesreplytocommand")
        {

            XmlNodeList yesreplytocommand = Responses.SelectNodes("MarcusXMLFile/response/greatmood/yes/replytocommand/answer");
            foreach (XmlNode ans in yesreplytocommand
                        .Cast<XmlNode>()
                        .OrderBy(elem => Guid.NewGuid()))
                    {
                        response = ans.InnerText;
                    }
        }
    }

and then to display:

QEvent = "yesreplytocommand";
Responses();
Console.WriteLine(response);

My problem is when it gets Settings.Default.User and displays it, I want it to display it as c# code so that it actually gets the value from the application. Right now it is actually displaying "Settings.Default.User". How do I do this?

Upvotes: 1

Views: 134

Answers (2)

Damir Arh
Damir Arh

Reputation: 17855

First, you'll need a way to recognize which of your entries are literals and which are expressions. You could do it by adding an attribute to the XML node:

<?xml version="1.0" encoding="utf-8" ?>
<MarcusXMLFile xmlns:Responses="http://www.rewardstrike.com/XMLFile1.xml">
  <response>
    <greatmood>
      <yes>
        <replytocommand>
          <answer>Yes.</answer>
          <answer>Yes, sir.</answer>
          <answer expression="true">DefaultSettings.User</answer>
        </replytocommand>
      </yes>
    </greatmood>
  </response>
</MarcusXMLFile>

Based on that you can modify your parsing code to either directly use the value from XML or evaluate it instead:

foreach (XmlNode ans in yesreplytocommand
    .Cast<XmlNode>()
    .OrderBy(elem => Guid.NewGuid()))
        {
            var attribute = ans.Attributes["expression"];
            if (attribute != null && attribute.Value == "true")
            {
                Console.WriteLine(Evaluate(ans.InnerText));
            }
            else
            {
                Console.WriteLine(ans.InnerText);
            }
        }

There's still the problem of evaluating that expression. There's no easy built-in way to do that from C#. But you could use Dynamic Expresso. This is how Evaluate method could look like:

public string Evaluate(string expression)
{
    var interpreter = new Interpreter();
    interpreter.SetVariable("DefaultSettings", Settings.Default);
    return interpreter.Eval<string>(expression);
}

As you can see, you'll still have to define the expression variables yourself. For the above to work, you will have to use DefaultSettings.User in your XML instead of Settings.Default.User. I already made that change in my sample XML at the beginning of the answer.

Upvotes: 3

Pontus Magnusson
Pontus Magnusson

Reputation: 651

You should take a look at XML Serialization.

Really basic on how it works is that it can convert a struct or a class like this:

struct Foo
{
    int bar = 0;
    Vector2 obj = new Vector2(10, 50);
}

into this:

<?xml version="1.0" ?> 
<Foo xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"">
<bar>0</bar>
<obj>
    <X>10</X>
    <Y>50</Y>
</ojb>
</Foo>

And the other way around.
The methods used to load and save code looks like this:

public static void Save(string filepath, Foo foobject)
{
    XmlSerializer serializer = new XmlSerializer(typeof(Foo));
    using (Stream stream = File.OpenWrite(filepath))
    {
        serializer.Serialize(stream, foobject);
    }
}

public static Foo Load(string filepath)
{
    Foo myFoo;
    XmlSerializer serializer = new XmlSerializer(typeof(Foo));
    using (Stream stream = File.OpenRead(filepath))
    {
        myFoo = (Foo)serializer.Deserialize(stream);
    }
}

It converts xml code to c# code, and other way around. It cannot convert methods, but it can convert most properties and classes.

Upvotes: 0

Related Questions