从XML文件中删除特定条目

时间:2014-09-08 11:14:24

标签: c# xml linq-to-xml

我有以下xml文件

- <annotations>
  - <annotation value="Black and white, outdoor" eventID="1">
          <image location="0928262.JPG" /> 
    </annotation>

  - <annotation value="CLear, obstacles" eventID="2">
          <image location="0928262.JPG" /> 
    </annotation>
  </annotations>

我有一个接收文件位置的函数,然后从xml文件中删除它,就像这样,

private void remEntry(String fName)
{
    string xmlFile = path + "\\output.xml";

    if (File.Exists(xmlFile))
    {
        XDocument xdoc = XDocument.Load(xmlFile);

        foreach (var x in xdoc.Descendants("annotation").ToList())
        {
            foreach (var el in xdoc.Descendants("image").ToList())
            {
                if (el.Attribute("location").Value == fName)
                {
                    el.Remove();

                }
            }
        }
        xdoc.Save(xmlFile);
    }
}

这样可行,但我遇到了问题,此代码将从xml文件中删除所有文件名实例,我只想删除与特定eventID绑定的文件名。事件ID在文本窗口中显示在应用程序中。所以,我在循环中添加了以下内容

foreach (var x in xdoc.Descendants("annotation").ToList())
{
    foreach (var el in xdoc.Descendants("image").ToList())
    {
        if (el.Attribute("location").Value == fName &&        
            x.Attribute("eventID").Value == eventID.Text)
        {
            el.Remove();

        }
    }

这里的想法是,如果图像名称等于输入,并且图像的eventID与显示的EventID相同,则删除该元素。但它仍然会删除文件名的所有实例。

这是预期的结果,其中eventID = 2。

- <annotations>
      - <annotation value="Black and white, outdoor
              <image location="0928262.JPG" /> 
        </annotation>

      - <annotation value="CLear, obstacles" eventID="2">

        </annotation>
      </annotations>

这是我得到的,

- <annotations>
      - <annotation value="Black and white, outdoor" eventID="1">

        </annotation>

      - <annotation value="CLear, obstacles" eventID="2">

        </annotation>
      </annotations>

4 个答案:

答案 0 :(得分:3)

将您的方法更改为以下内容,它将起作用

foreach (var x in xdoc.Descendants("annotation").ToList())
{
  foreach (var el in x.Descendants("image").ToList())
  {
    if (el.Attribute("location").Value == loc && x.Attribute("eventID").Value == id)
    {
      el.Remove();
    }
  }
}

第二个foreach需要获得第一个foreach提供的当前元素的后代。

您的代码始终从完整文档中获取后代,这导致当第一个foreach遇到带有eventID == 2的元素时,它将从完整文档中删除具有指定位置的所有图像。

答案 1 :(得分:2)

您可以使用XPath查询,而不是使用嵌入式 foreach 循环来查找要删除的节点。为此,首先必须导入 System.Xml.XPath 命名空间:

using System.Xml.XPath;

然后使用以下代码:

var id = 1;
var fileName = "0928262.JPG";
foreach (var x in xdoc.XPathSelectElements(String.Format(@"//annotation[@eventID={0}]/image[@location=""{1}""]", id, fileName)))
{
    x.Remove();
}

答案 2 :(得分:1)

我认为在内部foreach循环中你有xdoc.descendents(),它给你们两个图像元素。尝试使用x.Descendents() -

foreach (var el in x.Descendants("image").ToList())

答案 3 :(得分:1)

。似乎你的循环嵌套是不正确的。最初,您循环遍历文档中的所有注释: foreach (var x in xdoc.Descendants("annotation").ToList())并且您循环遍历文档中的所有图片:foreach (var el in xdoc.Descendants("image").ToList())

如果你要打印位置和eventID,你会得到这个:

  • eventID 1,0928262.JPG(第一个位置)
  • eventID 1,0928262.JPG(第二位置)
  • eventID 2,0928262.JPG(第一个位置)
  • eventID 2,0928262.JPG(第二位置)

正如您在此输出中所看到的,您将符合删除条目两次的条件。

你应该做的是:

foreach (var x in xdoc.Descendants("annotation").ToList())
{
    foreach (var el in x.Descendants("image").ToList())
    {
        if (el.Attribute("location").Value == fName &&
            x.Attribute("eventID").Value == eventID.Text)
        {
            el.Remove();
        }
    }
}