我有以下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);
}
}
如何修改上面的代码以达到我的目的?
答案 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;的文件名列表。