查找具有特定值 C# 的属性的元素

本文关键字:属性 元素 查找 | 更新日期: 2023-09-27 17:56:38

我有以下 Xml 文件

<?xml version="1.0" encoding="UTF-8"?>
<session xmlns="http://winscp.net/schema/session/1.0" name="test" start="2014-04-04T15:54:09.728Z">
  <upload>
    <filename value="D:'ftp'test1.TXT" />
    <destination value="/in/test1.TXT" />
    <result success="true" />
  </upload>
  <touch>
    <filename value="/in/test1.TXT" />
    <modification value="2014-03-27T12:45:20.000Z" />
    <result success="true" />
  <upload>
    <filename value="D:'ftp'test2.TXT" />
    <destination value="/in/test2.TXT" />
    <result success="true" />
  </upload>
  <touch>
    <filename value="/in/test2.TXT" />
    <modification value="2014-03-27T12:45:20.000Z" />
    <result success="false" />
  </touch>
</session>

我需要并且我想浏览filename节点where result success="true"的所有元素touchupload

我只会得到D:'ftp'test1.TXT

所以这是我的代码:

string file =@"C:''Program.xml";
            if (File.Exists(file))
            {
                try
                {
                    XElement root = XElement.Load(file);
                    IEnumerable<XElement> filename =
                        from el in root.Elements("upload")
                        where (string)el.Attribute("result success") == "true"
                        select el;
                    foreach (XElement el in filename)
                        Console.WriteLine(el);
                 }
              }

如何修改上面的代码以获得我的目的?

查找具有特定值 C# 的属性的元素

更新后:

void Main()
{
  XElement root = XElement.Parse (
  @"<?xml version='1.0' encoding='UTF-8'?>
<session  name='test' start='2014-04-04T15:54:09.728Z'>
  <upload>
    <filename value='D:'ftp'test1.TXT' />
    <destination value='/in/test1.TXT' />
    <result success='true' />
  </upload>
  <touch>
    <filename value='/in/test1.TXT' />
    <modification value='2014-03-27T12:45:20.000Z' />
    <result success='true' />
  </touch>
  <upload>
    <filename value='D:'ftp'test2.TXT' />
    <destination value='/in/test2.TXT' />
    <result success='true' />
  </upload>
  <touch>
    <filename value='/in/test2.TXT' />
    <modification value='2014-03-27T12:45:20.000Z' />
    <result success='false' />
  </touch>
</session>");
  var upload = from el in root.Elements("upload") select el;
  var touch = from el in root.Elements("touch") select el;
  // use zip to join the two lists together based on ordering to a new object
  // this WON'T work if the lists are different lengths!
  var filename = upload.Zip(touch,(u,t) => new { upload = u, touch = t })
        .Where(item => item.upload.Descendants("result").First().Attribute("success").Value  == "true" 
                   &&  item.touch.Descendants("result").First().Attribute("success").Value  == "true")
        .Select(item => item.upload.Descendants("filename").First().Attribute("value").Value);

  foreach (string el in filename)
    Console.WriteLine(el);
}

注意,我删除了XML内容上的命名空间以使其更清晰。 随意把它放回去。 (如果这样做,则必须在名称前面加上命名空间。

此外,我在 Linq 中这样做是因为有人要求这样做,我认为在上传和触摸数组上使用 for 循环会更快。

以下是您将如何执行此操作:

  var uploada = upload.ToArray();
  var toucha = touch.ToArray();
  List<string> filename = new List<string>();
  for(int index = 0; index < uploada.Length  ; index++)
  {
    if (uploada[index].Descendants("result").First().Attribute("success").Value  == "true" 
        && toucha[index].Descendants("result").First().Attribute("success").Value  == "true")
      filename.Add(uploada[index].Descendants("filename").First().Attribute("value").Value);
  }

这对我有用:

void Main()
{
  XElement root = XElement.Parse (
  @"<?xml version=""1.0"" encoding=""UTF-8""?>
<session  name=""test"" start=""2014-04-04T15:54:09.728Z"">
  <upload>
    <filename value=""D:'ftp'test1.TXT"" />
    <destination value=""/in/test1.TXT"" />
    <result success=""true"" />
  </upload>
  <touch>
    <filename value=""/in/test2.TXT"" />
    <modification value=""2014-03-27T12:45:20.000Z"" />
    <result success=""true"" />
  </touch>
</session>");
  var filename  = from el in root.Elements("upload")
                  where el.Descendants("result").First().Attribute("success").Value  == "true"
                  select el.Descendants("filename").First().Attribute("value").Value;

  Console.WriteLine(filename);
}

注意,我删除了XML内容上的命名空间以使其更清晰。 随意把它放回去。 (如果这样做,则必须在名称前面加上命名空间。

var xe = XElement.Parse(xml);
var ns = xe.Name.Namespace;
var filenames = from d in xe.Elements()
                let success =  d.Element(ns + "result").Attribute("success")
                where success != null & success.Value == "true"
                select d.Element(ns + "filename").Attribute("value").Value;
filenames.Dump();

这应该会返回一个结果为"true"的文件名列表。

我可能会使用 XPath,因为它会产生更干净的代码。

var filenamesXPath = "/session/*[result[@success='true']]/filename";
var filenames = document.XPathSelectElements(filenamesXPath);

但这不仅会因为缺少命名空间处理而起作用 - 您实际需要的是以下内容。

var document = XDocument.Load(file);
var namespaces = new XmlNamespaceManager(new NameTable());
namespaces.AddNamespace("ns", document.Root.GetDefaultNamespace().NamespaceName);
var filenamesXPath = "/ns:session/*[ns:result[@success='true']]/ns:filename";
var filenames = document.XPathSelectElements(filenamesXPath, namespaces);

试试这个:

var doc = XDocument.Parse(file);
XNamespace ns = "http://winscp.net/schema/session/1.0";
var elements = doc.Descendants(ns + "upload")
                  .Where(e =>
                     (string)(e.Element(ns + "result")
                               .Attribute("success")) == "true");

更新

由于此处的要求已更改,因此更新了解决方案:

string xml = @"<?xml version='1.0' encoding='UTF-8'?>
<session xmlns='http://winscp.net/schema/session/1.0' name='test' start='2014-04-04T15:54:09.728Z'>
  <upload>
    <filename value='D:'ftp'test1.TXT' />
    <destination value='/in/test1.TXT' />
    <result success='true' />
  </upload>
  <touch>
    <filename value='/in/test1.TXT' />
    <modification value='2014-03-27T12:45:20.000Z' />
    <result success='true' />
  </touch>
  <upload>
    <filename value='D:'ftp'test2.TXT' />
    <destination value='/in/test2.TXT' />
    <result success='true' />
  </upload>
  <touch>
    <filename value='/in/test2.TXT' />
    <modification value='2014-03-27T12:45:20.000Z' />
    <result success='false' />
  </touch>
</session>";
var doc = XDocument.Parse(xml);
XNamespace ns = "http://winscp.net/schema/session/1.0";
var fileNames = doc.Descendants(ns + "result")
    .Where(r => (string)r.Attribute("success") == "true")
    .Select(e => (string)e.ElementsBeforeSelf(ns + "filename").Single().Attribute("value"));

Single用于某些方案验证。按顺序,如果每个节点触摸或上传节点中没有确切的filename,您将获得异常。