开发者

XmlReader best practices

I've had a good read through MSDN and the XmlReader related questions on StackOverflow and I haven't yet come across a decent "best practices" example.

I've tried various combinations and each seems to have downsides, but the best I can come up with is as follows:

The XML:

<properties>
  <actions:name>start</actions:name>
  <actions:value type="System.DateTime">06/08/2011 01:26:49</actions:value>
</properties>

The code:

// Reads past the initial/root element
reader.ReadStartElement();

// Check we haven't hit the end
while (!reader.EOF && reader.NodeType != XmlNodeType.EndElement) {
    if (reader.IsStartElement("name", NamespaceUri)) {
        // Read the name element
        this.name = reader.ReadElementContentAsString();
    } else if (reader.IsStartElement("value", NamespaceUri)) {
        // Read the value element
        string valueTypeName = reader["type"] ?? typeof(string).Name;
        Type valueType = Type.GetType(val开发者_如何学CueTypeName);
        string valueString = reader.ReadElementContentAsString();
        // Other stuff here that doesn;t matter to the XML parsing
    } else {
        // We can't do anything with this node so skip over it
        reader.Read();
    }
}

This is being passed into my class from a .ReadSubTree() call and each class reads its own information. I would prefer it NOT to rely on it being in a specific order.

Before this, I did try several variations.

1) while(reader.Read()) This was taken from various example, but found that it "missed" some elements when .ReadContent*() of element 1 left it on the start of the element 2, .Read read over it to element 3.

2) Removing the .Read() caused it to just get stuck after the first element I read.

3) Several others I long consigned to "failed".

As far as I can see, the code I've settled on seems to be the most accepting and stable but is there anything obvious I'm missing?

(Note the c# 2.0 tag so LINQ/XNode/XElement aren't options)


One approach is to use a custom XmlReader. XmlReader is abstract and XmlReaders can be chained, giving a powerful mechanism to do some domain specific processing in a reader.

Example: XamlXmlReader

Help on XmlWrappingReader

Here's a sample of how it could be implemented (See inline comments):

/// <summary>
/// Depending on the complexity of the Xml structure, a complex statemachine could be required here.
/// Such a reader nicely separates the structure of the Xml from the business logic dependent on the data in the Xml. 
/// </summary>
public class CustomXmlReader: XmlWrappingReader
{
    public CustomXmlReader(XmlReader xmlReader)
        :base(XmlReader.Create(xmlReader, xmlReader.Settings))
    {

    }

    public override bool Read()
    {
        var b = base.Read();
        if (!b)
            return false;
        _myEnum = MyEnum.None;
        if("name".Equals(this.Name))
        {
            _myEnum = MyEnum.Name;
            //custom logic to read the entire element and set the enum, name and any other properties relevant to your domain
            //Use base.Read() until you've read the complete "logical" chunk of Xml. The "logical" chunk could be more than a element.
        }
        if("value".Equals(this.Value))
        {
            _myEnum = Xml.MyEnum.Value;
            //custom logic to read the entire element and set the enum, value and and any other properties relevant to your domain
            //Use base.Read() until you've read the complete "logical" chunk of Xml. The "logical" chunk could be more than a element.
        }
        return true;
    }
    //These properties could return some domain specific values
    #region domain specific reader properties. 
    private MyEnum _myEnum;
    public MyEnum MyEnum
    {
        get { return _myEnum; }
    }

    #endregion
}

public enum MyEnum
{
    Name,
    Value,
    None
}

public class MyBusinessAppClass
{
    public void DoSomething(XmlReader passedInReader)
    {

        var myReader = new CustomXmlReader(passedInReader);
         while(myReader.Read())
         {
             switch(myReader.MyEnum)
             {
                 case MyEnum.Name:
                     //Do something here;
                     break;
                 case MyEnum.Value:
                     //Do something here;
                     break;

             }
         }
    }
}

A word of caution : This might be over engineering for some simple Xml processing that you've shown here. Unless, you have more that two elements that need custom processing, this approach is not advised.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜