循环迭代父节点,直到找到特定标签
Loop to iterate up parent nodes until it finds specific tag
我正在做的是在 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 字符串以我想要的方式进行评估或者我该如何做到这一点以不同的方式达到相同的最终结果?
编辑:这是我的 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>
所以您实际上不需要执行这么多字符串操作就可以疯狂地使用 XPath。找到子目标元素后,您可以在 XElement
上迭代使用 Parent
属性,直到找到带有 private/public 标记的 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
已成为 private
或 public
标记。如果是后者,它会附加到您的结果中。
您可以使用 XElement.Ancestors
函数获取包含您找到的节点的所有元素的列表,然后仅 select 使用 LINQ 获取您想要的元素。不需要任何循环。
var results = fieldReferences.Select(element => element.Ancestors()
.Where(ancestor => ancestor.Name == "public" ||
ancestor.Name == "private")
.FirstOrDefault());
请注意,这将一直沿树向上,如果有多个匹配的祖先(或没有匹配的祖先),则可能会出现问题。如果这对您来说是个问题,请告诉我,在这种情况下您想要什么结果,我可以做出调整。
我正在做的是在 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 字符串以我想要的方式进行评估或者我该如何做到这一点以不同的方式达到相同的最终结果?
编辑:这是我的 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>
所以您实际上不需要执行这么多字符串操作就可以疯狂地使用 XPath。找到子目标元素后,您可以在 XElement
上迭代使用 Parent
属性,直到找到带有 private/public 标记的 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
已成为 private
或 public
标记。如果是后者,它会附加到您的结果中。
您可以使用 XElement.Ancestors
函数获取包含您找到的节点的所有元素的列表,然后仅 select 使用 LINQ 获取您想要的元素。不需要任何循环。
var results = fieldReferences.Select(element => element.Ancestors()
.Where(ancestor => ancestor.Name == "public" ||
ancestor.Name == "private")
.FirstOrDefault());
请注意,这将一直沿树向上,如果有多个匹配的祖先(或没有匹配的祖先),则可能会出现问题。如果这对您来说是个问题,请告诉我,在这种情况下您想要什么结果,我可以做出调整。