代码之家  ›  专栏  ›  技术社区  ›  BlueMonkMN

我永远无法预测XMLReader的行为。关于理解有什么建议吗?

  •  15
  • BlueMonkMN  · 技术社区  · 15 年前

    正如您所看到的,我对XMLReader在读取的各个阶段所处的位置以及它的状态如何受到各种读取函数的影响缺乏了解。是否有一些我根本没有注意到的简单模式?

    下面是问题的另一个例子(摘自回复):

    string input = "<machine code=\"01\">The Terminator" +
       "<part code=\"01a\">Right Arm</part>" +
       "<part code=\"02\">Left Arm</part>" +
       "<part code=\"03\">Big Toe</part>" +
       "</machine>";
    
    using (System.IO.StringReader sr = new System.IO.StringReader(input))
    {
       using (XmlTextReader reader = new XmlTextReader(sr))
       {
          reader.WhitespaceHandling = WhitespaceHandling.None;
          reader.MoveToContent();
    
          while(reader.Read())
          {
             if (reader.Name.Equals("machine") && (reader.NodeType == XmlNodeType.Element))
             {
                Console.Write("Machine code {0}: ", reader.GetAttribute("code"));
                Console.WriteLine(reader.ReadElementString("machine"));
             }
             if(reader.Name.Equals("part") && (reader.NodeType == XmlNodeType.Element))
             {
                Console.Write("Part code {0}: ", reader.GetAttribute("code"));
                Console.WriteLine(reader.ReadElementString("part"));
             }
          }
       }
    }
    

    下一个问题是,在读取第一个part元素时,ReadElementString似乎在读取后将读取器定位在下一个part元素的开头。这会导致下一个循环开头的reader.Read跳过下一个part元素,直接跳到最后一个part元素。所以这段代码的最终输出是:

    零件代码01a:右臂

    零件代码03:大脚趾

    这是我试图理解的XMLReader混淆行为的一个主要示例。

    2 回复  |  直到 15 年前
        1
  •  6
  •   Marc Gravell    15 年前

    事情是这样的。。。我已经编写了大量的序列化代码(包括许多xml处理),我发现自己陷入了困境 确切地 和你一样的船。我有一个非常简单的指导,因此: .

    我很乐意使用 XmlWriter 作为一种快速编写xml的方法,但在选择实现之前,我会仔细考虑一下 IXmlSerializable DTO 并将数据映射到其中;它还意味着模式(用于“mex”、“wsdl”等)是免费的。

        2
  •  3
  •   BlueMonkMN    15 年前

    我的最新解决方案(适用于我当前的情况)是在实现状态机时坚持使用Read()、isstartement(name)和GetAttribute(name)。

    using (System.Xml.XmlReader xr = System.Xml.XmlTextReader.Create(stm))
    {
       employeeSchedules = new Dictionary<string, EmployeeSchedule>();
       EmployeeSchedule emp = null;
       WeekSchedule sch = null;
       TimeRanges ranges = null;
       TimeRange range = null;
       while (xr.Read())
       {
          if (xr.IsStartElement("Employee"))
          {
             emp = new EmployeeSchedule();
             employeeSchedules.Add(xr.GetAttribute("Name"), emp);
          }
          else if (xr.IsStartElement("Unavailable"))
          {
             sch = new WeekSchedule();
             emp.unavailable = sch;
          }
          else if (xr.IsStartElement("Scheduled"))
          {
             sch = new WeekSchedule();
             emp.scheduled = sch;
          }
          else if (xr.IsStartElement("DaySchedule"))
          {
             ranges = new TimeRanges();
             sch.daySchedule[int.Parse(xr.GetAttribute("DayNumber"))] = ranges;
             ranges.Color = ParseColor(xr.GetAttribute("Color"));
             ranges.FillStyle = (System.Drawing.Drawing2D.HatchStyle)
                System.Enum.Parse(typeof(System.Drawing.Drawing2D.HatchStyle),
                xr.GetAttribute("Pattern"));
          }
          else if (xr.IsStartElement("TimeRange"))
          {
             range = new TimeRange(
                System.Xml.XmlConvert.ToDateTime(xr.GetAttribute("Start"),
                System.Xml.XmlDateTimeSerializationMode.Unspecified),
                new TimeSpan((long)(System.Xml.XmlConvert.ToDouble(xr.GetAttribute("Length")) * TimeSpan.TicksPerHour)));
             ranges.Add(range);
          }
       }
       xr.Close();
    }
    

    读取后,如果您只读取一个开始元素(可选地检查读取元素的名称),IsStartElement将返回true,并且您可以立即访问该元素的所有属性。如果您只需要阅读元素和属性,那么这非常简单。

    编辑 问题中的新例子提出了一些其他挑战。读取该XML的正确方法如下所示:

    using (System.IO.StringReader sr = new System.IO.StringReader(input))
    {
       using (XmlTextReader reader = new XmlTextReader(sr))
       {
          reader.WhitespaceHandling = WhitespaceHandling.None;
    
          while(reader.Read())
          {
             if (reader.Name.Equals("machine") && (reader.NodeType == XmlNodeType.Element))
             {
                Console.Write("Machine code {0}: ", reader.GetAttribute("code"));
                Console.WriteLine(reader.ReadString());
             }
             if(reader.Name.Equals("part") && (reader.NodeType == XmlNodeType.Element))
             {
                Console.Write("Part code {0}: ", reader.GetAttribute("code"));
                Console.WriteLine(reader.ReadString());
             }
          }
       }
    }
    

    经过一些额外的思考,我的观点是XMLReader太令人困惑了 如果 您可以使用read方法以外的任何方法来读取内容。我认为,如果您只使用Read方法来读取XML流,那么会简单得多。下面是它在新示例中的工作方式(再次说明,IsStartElement、GetAttribute和Read似乎是关键方法,您最终得到的是一个状态机):

    while(reader.Read())
    {
       if (reader.IsStartElement("machine"))
       {
          Console.Write("Machine code {0}: ", reader.GetAttribute("code"));
       }
       if(reader.IsStartElement("part"))
       {
          Console.Write("Part code {0}: ", reader.GetAttribute("code"));
       }
       if (reader.NodeType == XmlNodeType.Text)
       {
          Console.WriteLine(reader.Value);
       }
    }