为什么XmlReader跳过标签?

时间:2018-08-12 14:42:23

标签: c# .net xml xmlreader

XmlReader正在跳过标签,我不知道为什么。如果执行下面的代码,则会看到ID 123和789被打印出来,表示456被跳过。如果运行使用1234的备用内存流,您只会看到123和456打印,这意味着1234和789被跳过。

这是主要部分。完整的代码如下。我用流创建一个XML阅读器,有一个while循环,我检查了想要的深度(因为节点不在深度0处)。据我了解,$posts = Post::whereHas('category', function($query) use($id) { $query->where('parent_id', $id); })->paginate(2); {{ $posts->links() }} @foreach ($posts as $post) {{ $post->body }} @endforeach 会读取XML,直到标签关闭为止,这正是我想要的。然后,我简单地打印出id值。很简单,不到十行代码

XElement.ReadFrom(root) as XElement

如果我在var root = XmlReader.Create(fs); root.MoveToElement(); while (root.Read()) { if (root.NodeType == XmlNodeType.EndElement || root.Depth != 1) continue; var el = XElement.ReadFrom(root) as XElement; Console.WriteLine(el.Attribute("id").Value); } 之间插入换行符,它将不会跳过标签,但感觉像是一个创可贴,而且我不确定我的输入是否在</node><node>之后有换行符。


</node>

using System.Xml.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;

namespace nearMe
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var fs = new MemoryStream(UTF8Encoding.UTF8.GetBytes(@"<?xml version=""1.0"" encoding=""utf-8""?><test><node id=""123"">
        <tag k=""amenity"" v=""fuel"" />
    </node><node id=""456"">
        <tag k=""name"" v=""B"" />
    </node><node id=""789"">
        <tag k=""amenity"" v=""test"" />
    </node></test>")))
            {
                var root = XmlReader.Create(fs);
                root.MoveToElement();

                while (root.Read())
                {
                    if (root.NodeType == XmlNodeType.EndElement || root.Depth != 1)
                        continue;
                    var el = XElement.ReadFrom(root) as XElement;
                    if (el == null)
                        continue;
                    if (el.Name != "node")
                        continue;

                    Console.WriteLine(el.Attribute("id").Value);
                }
            }
        }
    }
}

3 个答案:

答案 0 :(得分:1)

您的错误在注释中指出了类似的问题:

  

调用[XElement.ReadFrom]会读取该元素并转到下一个元素,然后下一个[root.Read()]会再次读取下一个元素。如果它们恰好具有相同的名称并且是连续的,那么您实际上会错过一个元素。   (pbz

解决此问题的最简单方法是消除ReadFrom并继续从读者那里获得价值:

            while (root.Read())
            {
                if (root.NodeType != XmlNodeType.Element || 
                    root.Depth != 1 ||
                    root.Name != "node")
                    continue;

                Console.WriteLine(root.GetAttribute("id"));
            }

答案 1 :(得分:1)

using (var fs = new FileStream("test.xml", FileMode.Open, FileAccess.Read))
{
    var test = XElement.Load(fs);
    var nodes = test.XPathSelectElements("node[@id]");

    foreach (var node in nodes)
    {
        Console.WriteLine(node.Attribute("id").Value);
    }
}

答案 2 :(得分:0)

使用下面的代码。它不会跳过,而是使用xml阅读器。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {

             using (var fs = new MemoryStream(UTF8Encoding.UTF8.GetBytes(@"<?xml version=""1.0"" encoding=""utf-8""?><test><node id=""123"">
                            <tag k=""amenity"" v=""fuel"" />
                        </node><node id=""456"">
                            <tag k=""name"" v=""B"" />
                        </node><node id=""789"">
                            <tag k=""amenity"" v=""test"" />
                        </node></test>")))
            {
                XmlReader reader = XmlReader.Create(fs);

                while (!reader.EOF)
                {
                    if(reader.Name != "node")
                    {
                        reader.ReadToFollowing("node");
                    }
                    if(!reader.EOF)
                    {
                        XElement node = (XElement)XElement.ReadFrom(reader);
                        int id = (int)node.Attribute("id");
                        Console.WriteLine(id.ToString());
                    }
                }
            }
            Console.ReadLine();

        }
    }
}