循环以迭代父节点,直到找到特定标记

时间:2017-12-29 14:46:00

标签: c# loops xelement

我正在做的是在XML文档中查找特定值,然后我想向上遍历每个父级,直到找到具有特定标记名称的父级。

List<XElement> fieldReferences = new List<XElement>();
fieldReferences.AddRange(element.XPathSelectElements(string.Format("descendant::nameValue[@idref='{0}']", fieldName)));
fieldReferences.AddRange(element.XPathSelectElements(string.Format("descendant::nameValue[@value='{0}']", fieldName)));

string parentIterator = ".Parent";
string attributeValue = ".Attribute('id').Value";
string parentElementName = ".Name";
foreach (var value in fieldReferences)
{
    var parentField = string.Format("{0}{1}", parentIterator, parentElementName);
    while (value + parentField != "private" || value + parentField != "public")
        {
            // keep appending .Parent until it finds what it needs
        }
    //var parentField = value.Parent.Parent.Parent.Parent.Attribute("id").Value;
    outputFields.Add(parentField, name.FirstOrDefault());
}

我遇到的问题是,parentField将始终被评估为字符串,因此它永远不会实际检查值的.Parent.Name属性。

我不经常使用C#工作,所以我确信这样做更容易,所以我的问题是:如何让我的parentField字符串来评估我想要的方式OR如何以不同的方式实现相同的最终结果呢?

编辑:这是我的xml的样子。 XPAthSelectElement获取nameValue元素,我想迭代每个父元素,直到找到私有标记

<private id="I need to iterate upwards through each parent element until I find this one">
    <value>
      <request>
        <nameValues>
          <nameValue idref="I found this" />
          <nameValue value=""/>
        </nameValues>
      </request>
    </value>
  </private>

2 个答案:

答案 0 :(得分:1)

所以你实际上并不需要做很多字符串操作,然后对XPath发疯。找到子目标元素后,您可以迭代地使用Parent上的XElement属性,直到找到带有私有/公共标记的XElement。所以这给了我们这段代码:

foreach (XElement element in fieldReferences)
{
    XElement currentElement = element;
    while (currentElement.Parent != null)
    {
        currentElement = currentElement.Parent;
        if (currentElement.Name == "private" || currentElement.Name == "public") {
            outputFields.Add(currentElement, /* not sure what you want here */);
            break;
        }
    }
}

所以currentElement最初会以您示例中带有nameValue标记的元素开头。在while循环中,每次迭代currentElement都会更改为其父节点,直到不再有父节点或currentElement成为privatepublic标记。如果是后一种情况,则会将其附加到您的结果中。

答案 1 :(得分:1)

您可以使用XElement.Ancestors函数获取包含您找到的节点的所有元素的列表,然后只需使用LINQ选择您想要的节点。不需要任何循环。

var results = fieldReferences.Select(element => element.Ancestors()
                                                       .Where(ancestor => ancestor.Name == "public" ||
                                                                          ancestor.Name == "private")
                                                       .FirstOrDefault());

请注意,这将在树上一直向上,如果有多个匹配的祖先(或没有匹配的祖先),则可能会出现问题。如果这对您来说是个问题,请告诉我,在这种情况下您想要的结果是什么,我可以进行调整。