【问题标题】:XML parsing when node may or may not exist节点可能存在或不存在时的 XML 解析
【发布时间】:2016-01-13 12:21:28
【问题描述】:

请考虑以下示例 XML。我有一个类说 Dummy 包含两个字段 X 和 Y。通过 XML 解析,我想构建该类的对象列表。 X 和 Y 分别取仅在 B 父节点内部的 X 和 Y 标签的值。在 XML 中,X 和 Y 节点可能存在也可能不存在于 B 节点中。

 <DOC>
  <A>1</A>
  <B>
   <C>1</C>
   <D>1</D>
   <E>1</E>
   <X>Hello</X>
   <F>1</F>
   <G>1</G>
   <Y>Hi</Y>
  </B>
  <B>
   <C>1</C>
   <D>1</D>
   <E>1</E>
   <F>1</F>
   <G>1</G>
  </B>
 <H>
  <X>1</X> //ignore
  <Y>1</Y> //ignore
 </H>
<DOC>

对于上述 XML,我希望列表包含两个元素。第一组将有“Hi”,“Hello”,另一组将有“”,“”

我的 C# 解析代码看起来像这样

List<Dummy> dummyList = new List<Dummy>();
Dummy d = null;

 while (xmlReader.Read())
        {
            if (xmlReader.IsStartElement())
            {
                switch (xmlReader.Name)
                {
                   case "B":
                            d = new Dummy();
                            while(xmlReader.Name != "X")
                                xmlReader.Read();   // can go into infinite loop if there is no X node
                            xmlReader.Read();
                            d.X = xmlReader.Value;

                            while(xmlReader.Name != "Y")
                                xmlReader.Read();  // can go into infinite loop if there is no Y node
                            xmlReader.Read();
                            d.Y = xmlReader.Value;

                            dummyList.Add(d);
                            d = null;
                            break;
              }
       }
 }

上面的代码在第一个 B 节点上工作正常,但在第二个 B 节点上失败。 请让我知道你的想法。

【问题讨论】:

  • 这段代码失败了吗?请提供。
  • 在您的源代码中,您首先搜索“X”,然后搜索“Y”。你是故意的吗?

标签: c# xml


【解决方案1】:
bool waitingForXy = false;
while (xmlReader.Read())
{
    if (xmlReader.IsStartElement())
    {
        switch (xmlReader.Name)
        {
            case "B":
                d = new Dummy();
                waitingForXy = true;
                break;
            case "X":
                if (waitingForXy)
                {
                    d.X = xmlReader.ReadString();
                }
                break;
            case "Y":
                if (waitingForXy)
                {
                    d.Y = xmlReader.ReadString();
                }
                break;
        }
    }
    else if (xmlReader.NodeType == XmlNodeType.EndElement)
    {
        switch (xmlReader.Name)
        {
            case "B":
                waitingForXy = false;
                dummyList.Add(d);
                break;
        }
    }
}

这将在每个&lt;B&gt; 开始元素上创建一个虚拟实例,并等待&lt;X&gt;&lt;Y&gt; 出现,直到&lt;/B&gt; 结束元素。如果它们没有发生,d.Xd.Y 将保持为空。

【讨论】:

    【解决方案2】:

    第二个B节点失败是什么意思。

    正如我在第二个 B 节点中看到的那样,您没有任何 X 或 Y。这意味着当它进入 switch 和 case “B”时,您将开始 while 循环,直到它找到不再存在的 X。所以它一直读到最后,没有任何反应。您只需要阅读到 B 节点的末尾(这将确保您避免无限循环),如果没有 X 和 Y,您必须为它们手动制作空字符串。

    【讨论】:

      【解决方案3】:

      如果您使用的是 VS2013 SP2 或更高版本,您可以使用 Edit-&gt;Paste Special-&gt;Paste XML As Classes 将强类型类从原始 XML 复制并粘贴到您的代码中。请注意,您必须关闭您的最终 &lt;/DOC&gt; 并删除 cmets 才能正常工作!

      然后您可以使用以下代码从 XML 中的任何 B 中提取任何 X 和 Y 值到元组集合中:

      string xml = // TODO: Get XML as string.
      var myXml = (DOC)new XmlSerializer(typeof(DOC)).Deserialize(new StringReader(xml));
      var results = myXml.B.Select(x => Tuple.Create(x.X, x.Y));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-05-14
        • 1970-01-01
        • 2014-01-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多