查找具有特定值 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"
的所有元素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);
}
}
如何修改上面的代码以获得我的目的?
更新后:
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
,您将获得异常。