2

我希望通过 C# 解析一个相对复杂的 XML 文件,并将选择的数据存储到 SQL Server '08 数据库中。这是我希望从 XML 文件中提取的内容:

<educationSystem>
    <school>
        <name>Primary School</name>
        <students>
            <student id="123456789">
                <name>Steve Jobs</name>
                <other elements>More Data</other elements>
            </student>
            <student id="987654">
                <name>Jony Ive</name>
                <otherElements>More Data</otherElements>
            </student>
        </students>
    </school>
    <school>
        <name>High School</name>
        <students>
            <student id="123456">
                <name>Bill Gates</name>
                <other elements>More Data</other elements>
            </student>
            <student id="987654">
                <name>Steve Ballmer</name>
                <otherElements>More Data</otherElements>
            </student>
        </students>
    </school>
</educationSystem>

[在你问之前,不,这不是学校作业——我以学校/学生为例,因为原件要敏感得多。]

我能够(使用 XDocument/XElement)解析 XML 文件并获取所有学校名称、学生姓名和学生 ID 的列表,但是当它被添加到数据库中时,我最终得到的Bill Gates学生条目不到一秒学校。这一切都只是一行一行。

我正在寻找一种方法来实现这一目标:

Foreach school
    put it's name into an XElement
    foreach student
        grab the name and id put into XElements
Grab next school and repeat

我相信 Linq 将是实现这一目标的最佳方式,但我在如何开始这个过程时遇到了麻烦。有人能指出我正确的方向吗?

编辑:这是我目前用来将数据保存到数据库的代码。它一次处理一个列表(因此事情不应该是相关的)。我还将整理 SQL。

 private void saveToDatabase (List<XElement> currentSet, String dataName)
    {
        SqlConnection connection = null;

        try
        {
            string connectionString = ConfigurationManager.ConnectionStrings["connString"].ConnectionString + "; Asynchronous Processing=true";
            connection = new SqlConnection(connectionString);
            connection.Open();

            foreach (XElement node in currentSet)
            {
                SqlCommand sqlCmd = new SqlCommand("INSERT INTO dbo.DatabaseName (" + dataName + ") VALUES ('" + node.Value + "')", connection);

                sqlCmd.ExecuteNonQuery();
            }
        }
4

3 回答 3

1

此 LINQ 将生成一个具有两个属性的对象集合

  1. 学校名称

  2. 学生名单(又是一个集合)

     var result = XElement.Load("data.xml")
                   .Descendants("school")
                   .Select( x => new { 
                             name = XElement.Parse(x.FirstNode.ToString()).Value,
                             students =x.Descendants("student")
                                        .Select(stud => new { 
                   id = stud.Attribute("id"),
                   name = XElement.Parse(stud.FirstNode.ToString()).Value})
               .ToList()});
    

    注意:LINQ 假定为和标记<name>下的第一个节点<school><student>

  3. 然后你可以使用你想要的 foreach ,它会像魅力一样工作

     foreach (var school in result)
     {
        var schoolName = school.name;
        foreach (var student in school.students)
        {
                //Access student.id and student.name here                    
        }
     }
    
于 2012-11-09T15:02:21.427 回答
0

对于这种使用 XML 数据的特殊类型,您可以使用 XML 序列化/反序列化。

这将允许您将 XML 数据反序列化为 IEnumerable 类对象,在该类上执行 LINQ 查询,然后保存到 SQL。

希望这可以帮助。

于 2012-11-09T10:26:41.430 回答
0

更新:原始代码示例没有提到命名空间。在通过 XName 搜索元素时需要考虑命名空间,或者需要使用 XName.LocalName 属性进行搜索。更新了示例以显示在这种情况下如何处理选择元素。

namespace Stackover
{
    using System;
    using System.Xml.Linq;

    class Program
    {
        private const string Xml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
<namespaceDocument xmlns=""http://www.namedspace/schemas"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:schemaLocation=""http://www.namedspace/schemas.xsd"">
<educationSystem>
    <school>
        <name>Primary School</name>
        <students>
            <student id=""123456789"">
                <name>Steve Jobs</name>
                <otherElements>
                    <dataA>data</dataA>
                </otherElements>
            </student>
            <student id=""987654"">
                <name>Jony Ive</name>
                <otherElements>
                    <dataB>data</dataB>
                </otherElements>
            </student>
        </students>
    </school>
    <school>
        <name>High School</name>
        <students>
            <student id=""123456"">
                <name>Bill Gates</name>
                <otherElements>
                    <dataC>data</dataC>
                </otherElements>
            </student>
            <student id=""987654"">
                <name>Steve Ballmer</name>
                <otherElements>
                    <dataD>data</dataD>
                </otherElements>
            </student>
        </students>
    </school>
</educationSystem>
</namespaceDocument>";


        static void Main(string[] args)
        {
            var root = XElement.Parse(Xml);
            XNamespace ns = "http://www.namedspace/schemas";
            foreach(var school in root.Descendants(ns + "school")) // or root.Descendants().Where(e => e.Name.LocalName.Equals("school"));
            {
                Console.WriteLine(school.Element(ns + "name").Value);

                foreach (var students in school.Elements(ns+ "students"))
                {

                    foreach (var student in students.Elements())
                    {
                        Console.WriteLine(student.Attribute("id"));
                        Console.WriteLine(student.Name); // Name = namespace + XName
                        Console.WriteLine(student.Name.LocalName); // no namespace
                    }
                }
            }
        }

    }

}
于 2012-11-09T14:56:20.417 回答