开发者

How to consume constantly changing XML

Scenario:

Input:

  • An XML file whose structure constantly changes on the mercy of external team.
  • It's not a well formed XML.
  • Element Tags change too sometime.

Required Output:

  • A Object of predefined class which used by other parts of the application

Problem:

  • How do i map Changing Element tags with fixed Class names.

C# language.

enter code here
ReadIn("input.xml");

public static GbtInfo ReadIn(string path)
    {
        using (XmlReader reader = new XmlTextReader(path))
        {
            reader.ReadToDescendant("SYSTEM");
            return Serializers.ParseNode<GbtInfo>(reader);
        }
    }

public static T ParseNode<T>(XmlReader reader)
{
    Type t = typeof(T);
    return (T)ParseNode(t, reader);
}

public static object ParseNode(Type type, XmlReader reader)
{
    var instance = Activator.CreateInstance(type);

    IXmlSerializable xmlSerializable = instance as IXmlSerializable;
    if (xmlSerializable != null)
    xmlSerializable.ReadXml(reader);
    return instance;
}

public static object ParseNode(string name_space, string elementName, XmlReader reader)
{
    Type t = Type.GetType(name_space + "." + elementName, false, true);
    return ParseNode(t, reader);
}





public void ReadXml(System.Xml.XmlReader reader)
    {
        this.reader = reader;
        string nextElement;
        parent = reader.Name;
        PropertyInfo propertyinfo = null;

        //Setting a flag if the current node is empty.
        bool isEmptyElement = reader.IsEmptyElement;
        //Code that parses the attributes out of the Node.
        if (reader.HasAttributes)
        {
            for (int i = 0; i < reader.AttributeCount; i++)
            {
                reader.MoveToAttribute(i);
                nextElement = Utilities.RemoveSpecialChar(reader.Name);
                propertyinfo = (GetType()).GetProperty(nextElement, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
                if (propertyinfo != null)
                    propertyinfo.SetValue(this, reader.Value, null);
                else
                    PrintError(nextElement);


            }
        }
        if (!isEmptyElement)//if the element is not empty get all the children 
        {
            reader.Read();
            Utilities.SkipToContent(reader);
            while (!(reader.Name.Equals(parent) && reader.NodeType == XmlNodeType.EndElement))
            {
                reader.MoveToContent();
                //Case when Node Element is an object type with string 
                if (reader.NodeType == XmlNodeType.Text)
                {
                    propertyinfo = (GetType()).GetProperty("Value", BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);

                    if (propertyinfo != null)
                        propertyinfo.SetValue(this, reader.Value, null);
                    else
                        PrintError("Value");

                    //Testing Console.WriteLine(nextelement + " => " + reader.Value);
                    reader.Read();
                    Utilities.SkipToContent(reader);
                }
                if (reader.NodeType == XmlNodeType.Element)
                {
                    nextElement = Utilities.RemoveSpecialChar(reader.Name);
                    propertyinfo = (GetType()).GetProperty(nextElement, BindingFlags.IgnoreCase |开发者_Go百科 BindingFlags.Public | BindingFlags.Instance);
                    if (propertyinfo != null)
                    {
                        if (propertyinfo.PropertyType.FullName.Equals("System.String"))
                        {
                            reader.Read();//read to get the text
                            if (reader.NodeType != XmlNodeType.Text)
                                throw new InvalidOperationException("Special Case encountered check XML");
                            propertyinfo.SetValue(this, reader.Value, null);
                            //Testing Console.WriteLine(reader.Value);
                            reader.ReadToNextSibling("dummy");//this will read to the parent end tag
                            reader.Read();
                            Utilities.SkipToContent(reader);
                        }
                        else
                        {

                            System.Collections.IList list = propertyinfo.GetValue(this, null) as System.Collections.IList;
                            if (list != null)
                            {
                                list.Add(Serializers.ParseNode(Namespace, nextElement, reader));

                            }
                            else
                            {
                                propertyinfo.SetValue(this, Serializers.ParseNode(Namespace, nextElement, reader), null);
                            }
                        }
                    }
                    else
                    {
                        PrintError(nextElement);
                        reader.ReadToNextSibling();
                    }
                }
            }
        }

        //move to the next element
        reader.Read();
        Utilities.SkipToContent(reader);
    }


    // Utilities Method

      private void PrintError(string errorElement)
        {
            IXmlLineInfo info = reader as IXmlLineInfo;
            Log.LogIt("The attribute " + errorElement + " does not exist under " + parent + " Error Occurred at Line "
                      + info.LineNumber + " Col " + info.LinePosition, LogMessageType.Warning);
            info = null;
    }

     public static XmlReader SkipToContent(XmlReader reader)
        {
            int count = 0;
            while (reader.NodeType != XmlNodeType.Element && reader.NodeType != XmlNodeType.Attribute &&
                   reader.NodeType != XmlNodeType.EndElement && reader.NodeType != XmlNodeType.Text)
            {
                reader.Read(); count++;
                if (count > 2)
                {
                    //Console.WriteLine(" Stuck");
                    if (reader.EOF)
                    {
                        break;
                    }
                }
            }
            return reader;
        }

/// <summary>
/// Removes special symbols like "-","_","." from Node element name inorder to match it with the respective objects. 
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public static string RemoveSpecialChar(string str)
        {
            str = str.Replace("-", "");
            str = str.Replace(".", "");
            str = str.Replace("_", "");
            return str;
    }


First, you should force your external team to give you at least a syntactically correct XML file. This is an organizational issue, but if you cannot solve this, everything else does not make much sense.

A Object of predefined class which used by other parts of the application

Use an XmlDocument. Access the content dynamically in your code, and deal with the situation when there is a missing tag or block at runtime. Avoid mapping of element tags to statically defined attributes in a C# class as long as you don't know the element tag won't change any more in the next iteration. And if your code relies on some specific element tags, define them as string constants once in a central place in your code so you change them easily whenever a tag is renamed by the external team.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜