【问题标题】:Retrieving specific elements from an XDocument based on a list基于列表从 XDocument 中检索特定元素
【发布时间】:2016-09-06 20:23:17
【问题描述】:

我有一个存储在类中的 xml 元素列表:

public class clsField
{
    public string fieldName { get; set; }
}

然后我正在加载一个xml文件:

XDocument doc = XDocument.Load(fileName);

最后,我只想将上述类中定义的字段检索到 IEnumerable 对象中。这是我目前所拥有的:

List<clsField> lstFieldsToProcess;          
IEnumerable<XElement> allthedocs = from thedoc
                 in doc.Descendants("thedocs")
                 select
                 (
                  from fields
                  in lstFieldsToProcess
                  select XElement.Parse(fields.fieldName)
                 );

但是上面的代码出错了。任何帮助,将不胜感激。先谢谢了。

更新 #1

伪代码:

var fieldNames = new HashSet<string>(lstFieldsToProcess.Select(c => c.fieldName));
IEnumerable<XElement> elems = from level1 in doc.Elements("thedocs")
                              let level2 = level1.Descendants()
                              where fieldNames.Contains(level2.Name.LocalName)
                              select level1;

【问题讨论】:

  • getting an error on the above code 分享给我们怎么样?
  • clsField是序列化到fileName文档中的对象吗?或者您是否有序列化的任意对象,并且您想获取 another 类的属性名称(在本例中为类clsField),并且仅从 xml 文档中检索与该属性匹配的字段在clsField?中找到的名字?
  • 后者是正确的。 clsField 是一个单独的类,其中包含我想从“XDocument doc”中检索的字段的属性名称。谢谢。

标签: c# linq linq-to-xml


【解决方案1】:

我不太确定你想做什么。是否要过滤掉所有具有特定名称并且是名为“thedocs”的元素的后代的元素?

假设这是您想要做的,那么您可以执行以下操作:

IEnumerable<XElement> elems = from field in lstFieldsToProcess
                              from de in doc.Elements("thedocs").Descendants(field.fieldName)
                              select de;

// Of course this is the same:
IEnumerable<XElement> elems = lstFieldsToProcess
    .SelectMany(f => doc.Elements("thedocs").Descendants(f.fieldName));

我不确定 XDocument 的效率如何,所以最好先取出您想要匹配的字段名(如果性能对您很重要,请测试两者中哪个更好):

var fieldNames = new HashSet<string>(lstFieldsToProcess.Select(c => c.fieldName));
IEnumerable<XElement> elems = from d in doc.Elements("thedocs").Descendants()
                              where fieldNames.Contains(d.Name.LocalName)
                              select d;

更新 #1 我想你的伪代码中几乎都有它自己。

var fieldNames = new HashSet<string>(lstFieldsToProcess.Select(c => c.fieldName));
IEnumerable<XElement> elems = from level1 in doc.Elements("thedocs")
                              from level2 in level1.Descendants()
                              where fieldNames.Contains(level2.Name.LocalName)
                              select level1;

尽管如此,这可以多次包含相同的“thedocs”元素(如果它有多个具有有效字段名的后代)。为避免这种情况,只需在结果上调用 Distint()。

【讨论】:

  • 肯尼特谢谢!差不多了。它确实从后代中正确选择了字段。现在我如何返回:“doc.Elements("thedocs")" 而不是 "doc.Elements("thedocs").Descendants"?选择了这些字段,但我需要的最终格式只是“doc.Elements(“thedocs”)”。谢谢。
  • @RobertSmith:你说的“回来”是什么意思?如果您以任何方式更改这些元素(例如 Value),它们实际上也会在内存中的 doc 变量中更改。因此,要将新的 xml(具有更改的值)作为字符串(每个“theDocs”元素一个),您可以简单地执行:doc.Elements("theDocs").Select(e =&gt; e.ToString()) 当然,如果您只有一个“theDocs”元素,您可以改为:doc.Element("theDocs").ToString()
  • 肯尼特,这很难解释。请参阅上面的“更新 #1”。需要选择的字段更深一层(上面的“level2”)。但是select语句需要选择“level1”。
  • Kennet,也忘了上面的“更新#1”是伪代码。它不起作用,但它具有我正在寻找的基本概念。感谢您的帮助。
  • @RobertSmith:我更新了我的答案,希望这就是你所追求的。 (抱歉回复慢)。
猜你喜欢
  • 2019-03-27
  • 2013-09-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-25
  • 2013-10-28
  • 2013-12-30
  • 1970-01-01
  • 2018-09-22
相关资源
最近更新 更多