C# 递归解析xml文件

原创 2018年04月15日 10:56:44

 第一次写解析xml文件算是顺利搞定,没想到后来陆续提出了更多的需求,主要是遇到以下几个问题:

  1. load整个文件。

  2. 代码专用了。

  3. 存在多个同名元素。

        



        对于问题1,load整个文件这个问题。既然不能将上G的文件一次性load进内存,那就改用流读取(stream)的形式。在网上找到一个不错的读取函数,IEnumerable<XElement> StreamXElements(string uri, string matchname),输入xmlFileUri,以及需要匹配的元素的名字matchname,即可以IEnumerable的形式返回,这样写代码时可以foreach了。StreamXElements的具体代码如下:

static IEnumerable<XElement> StreamXElements(string uri, string matchname)
        {
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.IgnoreComments = true;
            settings.IgnoreWhitespace = true;

            using (XmlReader reader = XmlReader.Create(uri, settings))
            {
                reader.MoveToContent();
                while (!reader.EOF)
                {
                    if (reader.NodeType == XmlNodeType.Element
                        && reader.Name == matchname)
                    {
                        XElement el = XElement.ReadFrom(reader) as XElement;
                        if (el != null)
                        {
                            yield return el;
                        }
                    }
                    else
                    {
                        reader.Read();
                    }
                }
            }
        }

       对于问题2,代码专用,因为后边陆续查看了几个xml的Schema,发现什么深度的都有,所以考虑采用递归的形式去解决这块问题,即递归不断的去下钻子代,直到边界条件:1、无子代;或2、子代为item元素。递归这块的伪代码是:

static Dictionary<string, string> getDic(输入的eleArg,输入的key)
{
    if (eleArg有子代)
    {
        if (eleArg的子代是不是item)
        {
            // 有子代,且是item,
            // 则按照处理item的方式做处理,返回dic
        }
        else
        {
            // 有子代,但不是item
            // 则继续下钻,下钻时,将不断延伸的key传递下去
            foreach (遍历eleArg的每一个子代eleSon)
            {
                // MergeDic,合并字典用的
                dic = MergeDic(dic, getDic(eleSon, key+=eleArg的name);
            }
        }
    }
    else
    {
        // 没有子代,到头了。
        // 则按照处理末端元素的方式,返回dic
    }
    return dic;
}

        具体代码为:

static Dictionary<string, string> getDic(XElement ElementArg, string keyArg)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
             if (ElementArg.HasElements)
            {
                XElement ele = ElementArg.FirstNode as XElement;
                if (ele.Name.ToString().Equals("item"))
                {
                    // 有子代,且是item,则对ElementArg的子代开做处理,返回dic
                    IEnumerable<XElement> items = from temp in ElementArg.Elements("item")
                                                  select temp;
                    foreach (var item in items)
                    {
                        string strKey = keyArg + ElementArg.Name.ToString() + "_" + item.Element("name").Value.ToString() + "_";
                        string strValue = item.Element("value").Value.ToString();
                        dic.Add(strKey, strValue);
                    }
                    return dic;
                }
              else
              {
                  // 有子代,但不是item,则继续下钻。下钻时,将不断延伸的key传递下去
                  IEnumerable<XElement> items = ElementArg.Elements();
                  foreach (var item in items)
                  {
                       dic = MergeDic(dic, getDic(item, keyArg + ElementArg.Name.ToString() + "_"));
                  }
                }
              }
            else
            {
                // 没有子代,到头了。则返回 name-value
                string strKey = keyArg + ElementArg.Name.ToString() + "_";
                string strValue = ElementArg.Value.ToString();
                dic.Add(strKey, strValue);
            }

            return dic;
       }

        对于问题3,同级别下存在同名元素。由于解决第二个问题时已采用递归的方式,那么同级别下的同名元素,最可能出现的地方,就是对同级别的每一个元素做下钻并返回值做字典合并时(上述伪代码中的MergeDic)会遇到。这里直接采用字段后添加序号的形式来处理,举例:某字段key为AAA,mergeDic遇到时,则新增字段为AAA_1,还有下一个,则为AAA_2。所以这里在MergeDic中加了个while循环判断containsKey,若该序号已存在,则往上累加。MergeDic,和GetSequenceNextCount的具体代码为:

static Dictionary<string, string> MergeDic(Dictionary<string, string> dic1, Dictionary<string, string> dic2)
        {
            Dictionary<string, string> dicRes = new Dictionary<string, string>(dic1);
            foreach (string key in dic2.Keys)
            {
                string newKey = key;
                while (dicRes.ContainsKey(newKey))
                {
                    newKey = GetSequenceNextCount(newKey);
                }
                dicRes.Add(newKey, dic2[key]);
            }

            return dicRes;
        }

private static string GetSequenceNextCount(string str)
        {
            string res;
            int count;

            Regex r = new Regex("\\d+$");
            var ms = r.Matches(str);
            if (ms.Count > 0)
            {
                int.TryParse(
                    ms.OfType<Match>().Last().ToString(), 
                    out  count);
                int nextCount = count + 1;
                res = str.Substring(0, str.Length - count.ToString().Length) + nextCount.ToString();
            }
            else
            {
                res = str + "1";
            }

            return res;
        }

        解决三个问题后,解析xml文件的主体就只剩下几行了(见下边代码块)。比如还是处理Topological.xml文件,对每一个Topological元素,只需一句dic = getDic(MatchEle, "")即可。

static void Main(string[] args)
        {
            string strFileUri = @"D:\aaa.xml";
            string strMatchname = "TrailNtwProtection";
            IEnumerable<XElement> MatchElements = StreamXElements(strFileUri, strMatchname);

            Dictionary<string, string> dic = new Dictionary<string, string>();
            foreach (var MatchEle in MatchElements)
            {
                dic = getDic(MatchEle, "");
                // do sth with dic 
                dic.Clear();
            }
        }

 比如TopologicalLink.xml文件:

 比如TrailNtwProtection.xml文件:


       就这样,不管采集平台那边来什么xml文件都可以解析了。下一步就看看窗口界面怎么写了,定时更新、多个文件的勾选、单击运行、FTP的文件目录、下载、解压缩。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/muxiong0308/article/details/79946062

Python-递归

​是指函数/过程/子程序在运行过程序中直接或间接调用自身而产生的重入现象。 在计算机编程里,递归指的是一个过程:函数不断引用自身,直到引用的对象已知。
  • 2017年08月21日 14:22

XML(3)XDocument与XmlDocument递归读取xml文件

通过XDocument与XmlDocument将xml文件读取到TreeView上,其中主要是用递归方式将xml下的元素都加载到TreeView控件上面。 XDocument 步骤: (1)加载...
  • IstarI
  • IstarI
  • 2016-06-01 19:59:14
  • 960

C# <em>递归</em>遍历多层目录并将目录信息写入<em>XML</em>

C# <em>递归</em>遍历多层目录并将目录信息写入<em>XML</em> 代码简单为控制台代码不涉及窗口 ...上传者: njg2005 时间: 2009-06-<em>23</em> 综合评分: 4 积分/<em>C</em>币:3 C#...
  • 2018年03月23日 00:00

一种基于简单递归思想的易操控xml解析封装(C++)

一种基于简单递归思想的易操控xml解析封装 C++
  • lonelyrains
  • lonelyrains
  • 2015-04-17 10:34:58
  • 1296

递归

package recurrencesDemo;//递归算法,求阶乘,自身调用自身public class Factorial {public static void main(String[] ar...
  • weixin_39830306
  • weixin_39830306
  • 2017-08-21 16:39:25
  • 46

c#:用xml递归存电脑指定路径的目录

public static void StoreAllFilesToXml(string directoryPath, string destinationXmlFilePath, XmlNode p...
  • u014571132
  • u014571132
  • 2016-08-17 18:00:06
  • 568

递归

递归注意事项: A:递归一定到递归出来,要设置一个条件,当条件满足的时候就退出递归 B:递归的次数不能太多,否则就内存溢出,因为每递归异常,都产生一个线程 C:构造方法不能递归使用 // 有一...
  • zhou920786312
  • zhou920786312
  • 2017-04-05 11:59:31
  • 106

递归算法

递归算法 ​ 在函数或子过程的内部,直接或者间接地调用自己的算法。特点: (1) 递归就是在过程或函数里调用自身。 (2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。 ...
  • qq_38265137
  • qq_38265137
  • 2017-08-25 13:12:38
  • 193

C# 递归遍历多层目录并将目录信息写入XML

  • 2017年11月14日 14:13
  • 22KB
  • 下载

使用递归解析给定的任意一个xml文档并且将其内容输出到命令行上

import java.io.File;      import javax.xml.parsers.DocumentBuilder;   import javax.xml.parsers.Do...
  • u010267906
  • u010267906
  • 2016-01-26 15:19:15
  • 181
收藏助手
不良信息举报
您举报文章:C# 递归解析xml文件
举报原因:
原因补充:

(最多只允许输入30个字)