如何使用不断变化的 XML

发布于 2024-12-09 11:41:21 字数 6657 浏览 0 评论 0原文

场景:

输入:

  • 一个 XML 文件,其结构根据外部团队的控制不断变化。
  • 它不是一个格式良好的 XML。
  • 元素标签有时也会改变。

所需的输出:

  • 应用程序其他部分使用的预定义类的对象

问题:

  • 如何将更改元素标记与固定类名称映射。

C#语言。

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 | 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;
    }

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 | 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;
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

不念旧人 2024-12-16 11:41:21

首先,您应该强制外部团队至少为您提供一个语法正确的 XML 文件。这是一个组织问题,但如果你不能解决这个问题,其他一切都没多大意义。

应用程序其他部分使用的预定义类的对象

使用 XmlDocument。在代码中动态访问内容,并处理运行时缺少标签或块的情况。只要您不知道元素标签在下一次迭代中不会再发生变化,就避免将元素标签映射到 C# 类中静态定义的属性。如果您的代码依赖于某些特定的元素标签,请在代码的中心位置将它们定义为字符串常量,以便在外部团队重命名标签时轻松更改它们。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文