【问题标题】:Xml reader skipping valuesXml 阅读器跳过值
【发布时间】:2013-07-01 09:28:28
【问题描述】:

我有以下 XML sn-p-

-<Row>
 <RowType Id="1"Label="Scotland">1985</RowType>
 <Year Id="11"Label="1994"/>
 <Value Id="123">18</Value>
 <Field Id="123"Label="Country">16</Field>
 <Field Id="123"Label="Soccer">Yes</Field>
</Row>
-<Row>
 <RowType Id="1"Label="England">1986</RowType>
 <Year Id="11"Label="1994"/>
 <Value Id="123">19</Value>
 <Field Id="123"Label="Country">16</Field>
 <Field Id="123"Label="Soccer">Yes</Field>
</Row>
-<Row>
 <RowType Id="1"Label="Wales">1987</RowType>
 <Year Id="11"Label="1994"/>
 <Value Id="123">20</Value>
 <Field Id="123"Label="Country">16</Field>
 <Field Id="123"Label="Soccer">Yes</Field>
</Row>

我正在使用XmlReader 从中检索特定数据,就像这样 -

using (XmlReader reader = XmlReader.Create(new StringReader(xml)))
        {
            string country = "";
            string Year = "";
            string count = "";
            string tss= "";
            string tss2 = "";


            reader.MoveToContent();
            while (reader.Read())
            {

                reader.ReadToFollowing("RowType");
                country = reader.GetAttribute("Label");
                country = country.Replace("'", "");

                reader.ReadToFollowing("Year");
                Year = reader.GetAttribute("Label");

                reader.ReadToFollowing("Value");
                count = reader.ReadElementContentAsString();

                reader.ReadToFollowing("Field");
                tss = reader.GetAttribute("Label");

                reader.ReadToFollowing("Field");
                tss2 = reader.GetAttribute("Label");
            }
        }

这在第一次迭代中运行良好,但在第二次迭代中,它从 XML 中的第三行检索值,并继续跳到它应该解析的行之后的下一行。

我该如何解决这个问题?

【问题讨论】:

    标签: c# xml-parsing xmlreader


    【解决方案1】:

    其实你的代码是对的;不正确的是文件的结构。或者更好的是,您的代码不考虑文档的特定结构。

    您可以通过添加以下位来更改它:

    XmlReaderSettings settings = new XmlReaderSettings();
    settings.ConformanceLevel = ConformanceLevel.Fragment;
    using (XmlReader reader = XmlReader.Create(new StringReader(xml), settings))
    

    默认情况下,XMLReader 需要ConformanceLevel.Document,因此文件应该具有如下结构:

    <main>
    <Row id="5">
     <RowType Id="1" Label="Scotland">1985</RowType>
     <Year Id="11" Label="1994"/>
     <Value Id="123">18</Value>
     <Field Id="123" Label="Country">16</Field>
     <Field Id="123" Label="Soccer">Yes</Field>
    </Row>
    <Row id="1">
     <RowType Id="1" Label="England">1986</RowType>
     <Year Id="11" Label="1994"/>
     <Value Id="123">19</Value>
     <Field Id="123" Label="Country">16</Field>
     <Field Id="123" Label="Soccer">Yes</Field>
    </Row>
    <Row id="4">
     <RowType Id="1" Label="Wales">1987</RowType>
     <Year Id="11" Label="1994"/>
     <Value Id="123">20</Value>
     <Field Id="123" Label="Country">16</Field>
     <Field Id="123" Label="Soccer">Yes</Field>
    </Row>
    </main>
    

    我了解元素之间缺乏分隔(例如,Id="1"Label="Scotland" 而不是 Id="1" Label="Scotland")是一个错字,因为在任何情况下都必须存在分隔。

    ------------------- 更新

    您报告说,即使更改了一致性级别,您的代码也没有提供预期的结果。我对您的代码进行了新的测试,它运行良好;至少,它可以正确迭代。因此,我的理解是您想要检索与您的代码不同的值(它混合了应用程序名称、属性和内容)。

    你可以在下面看到我自己的代码(尽管我坚持你的也可以遍历给定的信息),这比你的更具适应性;我还在我认为您想要检索与您的代码不同的信息的部分中包含了一些 cmets。基本思想只是从内容(内容)中检索信息,但您的代码可以从任何地方获取信息。

            string path = @"XML file";
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.ConformanceLevel = ConformanceLevel.Fragment;
            using (XmlReader reader = XmlReader.Create(path, settings))
            {
                string country = "";
                string Year = "";
                string count = "";
                string tss = "";
                string tss2 = "";
    
                while (reader.ReadToFollowing("Row"))
                {
                    XmlReader reader2 = reader.ReadSubtree();
                    while (reader2.Read())
                    {
                        if (reader2.NodeType == XmlNodeType.Element)
                        {
                            if (reader2.Name == "RowType")
                            {
                                country = reader2.GetAttribute("Label");
                                country = country.Replace("'", ""); //country_year = reader.ReadElementContentAsString(); -> "Scotland" -> 1985
                            }
                            else if (reader2.Name == "Year")
                            {
                                //IF XML IS -> <Year Id="11">1994<Year/>
                                //Then -> Year = reader2.GetAttribute("Label")
                                Year = reader2.GetAttribute("Label"); //-> 1994
                            }
                            else if (reader2.Name == "Value")
                            {
                                count = reader2.ReadElementContentAsString(); 
                            }
                            else if (reader2.Name == "Field")
                            {
                                if (reader2.GetAttribute("Label") == "Country")
                                {
                                    tss = reader2.ReadElementContentAsString(); //I understand that this is what you want to read, instead the Label name
                                }
                                else if (reader2.GetAttribute("Label") == "Soccer")
                                {
                                    tss2 = reader2.ReadElementContentAsString();//I understand that this is what you want to read, instead the Label name
                                }
                            }
                        }
                    }
                }
            }
    

    这应该会提供您正在寻找的东西;或者,在最坏的情况下,对如何处理 XML 读取有一个非常清晰的想法。此外,包含一个 try...catch 可能是一件好事,以防万一;请注意,读取/处理变量时的任何错误都会导致读取过程立即停止。

    【讨论】:

    • 不幸的是,我添加了您的额外代码,但仍然没有按正确的顺序检查 XML...
    • 我会以不同于您所做的方式实现 XML 读取部分。但是我确实测试了您的代码(在更改 ConformanceLevel 之后)并且工作正常!?我可以更改它(以我通常处理这种 XML 读取情况的方式),但现在不行,因为我正在做其他事情。我可以过一会儿再来这里更新我的答案。
    • 非常感谢您的宝贵时间,我对“readToFollowing”部分缺乏了解,我猜这可能是问题所在。
    • 第一个问题是一致性级别,它在第一次迭代后引发了“崩溃”(= 停止阅读并退出循环)。您遇到的另一个问题是您忽略了主要/次要节点,只是盲目地使用 readToFollowing。但是,如前所述,经过快速测试,您的代码似乎运行良好。将在一段时间内对其进行测试并包含我自己的代码。没问题,我把这种“小作品”当作我主要的、压力很大的工作中的放松停顿:)
    • 我已经更新了我的答案。请看一下新代码(主要是假设)并告诉我您的印象。
    【解决方案2】:

    如果您愿意,我们可以使用 LINQ 来完成这项工作。

    如果您真的想将 Xml 中的所有值读取到某个变量中...您可以尝试类似的行...

            XElement po = XElement.Load(@"SoccerCup.xml");
            IEnumerable<XElement> childElements =
                from el in po.Elements()
                select el;
            foreach (XElement el in childElements)
            {
                var Year=el.Element("Year").Value;
                var country  = el.Element("country").Value;
                var count =el.Elemet("Value").Value;
                Console.WriteLine("Year: " + Year);
                Console.WriteLine("Country: " + country);
                Console.WriteLine("Count: " + count);
            }
    

    希望这会有所帮助...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多