0

我有一个 XML 文件,看起来像...

<Modules>
    <Module Title='Mod1' Attr2='' Attr3=''>
        <Functions>
            <Function Title='Fun1' Attr2=''>
                <SubFunctions>
                    <SubFunction Title='SubFun1' Attr2='' />
                    <SubFunction Title='SubFun2' Attr2='' />
                </SubFunctions>
            </Function>
            <Function Title='Fun2' Attr2='' />
            <Function Title='Fun3' Attr2='' />
         </Functions>
</Module>
<Module Title='Mod2' Attr2='' Attr3=''>
    <Functions>
    </Functions>
</Module>
<Module Title='Mod3' Attr2='' Attr3=''>
    <Functions>
    </Functions>
</Module>

我一直在尝试使用 C# 中的 LINQ 和 XML 编写基于递归性质的通用函数,但无法使函数尽可能通用。

我目前拥有的是我的函数加载所有与“模块”相关的数据,因此根据上述 XML 数据计数为 3。当用户选择“Mod1”第一个“模块”时,它应该加载此“Mod1”下的所有相应数据,即Fun1、Fun2、Fun3。同样,如果用户选择 Fun1,它应该加载此“Fun1”下的所有数据,即 SubFun1、SubFun2 等。

请注意:我不想在我的 C# 应用程序中硬编码任何 XML 标记。

提前致谢。

4

1 回答 1

0

如果您不想硬编码标签的名称,我们应该对 XML 结构做一个假设。根据您的示例,似乎有两种元素:

  1. “容器”元素。模块、函数、子函数。哪个可以包含零个或多个“数据”元素
  2. “数据”元素。模块、函数、子函数。它可以包含零个或一个“容器”元素,并且始终具有用于选择的“标题”属性。

请注意,除非您使用自定义名称,否则“标题”属性名称是硬编码的。你的决定。

代码可以是通用的,因为我们不关心元素的名称,而只关心它们的关系。如您所述,用户逐渐选择所选元素,按照此要求,我将提出以下解决方案:

MyXmlReader - 提供对 XML 文件的访问的类 DataElement - 包含有关查询元素的数据的类,包括其子元素

 class MyXmlReader
{
    // refference to current list element
    XmlNode currentListElement = null;
    XmlDocument xml;

    // load file, initialize  and return data that contains info ablut
    // the first level elements names
    public DataElement Load(string path)
    {
        xml = new XmlDocument();
        xml.Load(path);
        Init();
        DataElement result = new DataElement();
        result.SubTitles = GetChildTitles();
        return result;
    }

    // Initialize the reader to read from the beggining
    public void Init()
    {
        currentListElement = xml.DocumentElement;
    }

    // Get next child
    public DataElement GetNext(string title)
    {
        string tempTitle;

        foreach (XmlNode child in currentListElement.ChildNodes)
        {
            DataElement result = null;

            if (child.Attributes["Title"].Value == title)
            {
                // create object that contains the data about the child nodes Titles
                result = new DataElement();
                result.Title = child.Attributes["Title"].Value;

                if (child.FirstChild != null) // means no child nodes
                {
                    currentListElement = child.FirstChild;

                    // add subelements subtitles
                    result.SubTitles.AddRange(GetChildTitles());
                }
                return result;


            }
        }
        return null;
    }


    public List<string> GetChildTitles()
    {
        List<string> result = new List<string>();

        foreach (XmlNode child in currentListElement.ChildNodes)
        {
            result.Add(child.Attributes["Title"].Value);
        }
        return result;
    }


}


// add any other data to this class
// that you need about the element you return
class DataElement
{
    public List<string> SubTitles = new List<string>();
    public string Title { get; set; }
}

测试:

// test
    static void Main(string[] args)
    {
        MyXmlReader reader = new MyXmlReader();
        DataElement data = reader.Load("Data.xml");

        // Generic test:

        // get first module
        data = reader.GetNext(data.SubTitles[0]);
        // get first function 
        data = reader.GetNext(data.SubTitles[0]);
        // get first sub-function 
        data = reader.GetNext(data.SubTitles[0]);         


        // you can write test with hardcode nodes names like this:
        reader.Init();
        // get first module
        data = reader.GetNext("Mod1");
        // get first function 
        data = reader.GetNext("Fun1");
        // get first sub-function 
        data = reader.GetNext("SubFun1");  

        Console.Read();
    }
于 2013-09-13T13:30:00.317 回答