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

时间:2014-04-04 21:03:00

标签: c# xml

我有以下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>

我需要并且我想浏览节点filenamewhere result success="true"的所有touch元素upload

我只会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);
                 }
              }

如何修改上面的代码以达到我的目的?

4 个答案:

答案 0 :(得分:1)

更新后:

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内容上取出了命名空间,使其更加清晰。请随意重新输入。(如果你这样做,你必须在命名空间前加上你的名字前缀。)

答案 1 :(得分:0)

我可能会使用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);

答案 2 :(得分:0)

试试这个:

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,您将获得例外。

答案 3 :(得分:0)

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();

这应该返回一个包含结果&#34; true&#34;的文件名列表。