1

如何获取当前 XML 标记的索引?

例子:

<User>
  <Contact>
    <Name>Lucas</Name>
  </Contact>
  <Contact>
    <Name>Andre</Name>
  </Contact>
    ...
</User>

我正在尝试下面的代码

    foreach (var element2 in doc2.Root.Descendants())
    {
        String name = element.Name.LocalName;
        String value = element.Value;
    }

我想知道我是在读第一个<Contact>标签,还是第二个,还是第三个……

4

6 回答 6

5

使用Select的适当重载将在您枚举集合时产生索引。

var userContacts = doc2.Root
                       .Descendants()
                       .Where(element => element.Name == "Contact")
                       .Select((c, i) => new {Contact = c, Index = i});

foreach(var indexedContact in userContacts)
{
     // indexedContact.Contact
     // indexedContact.Index                 
}

注意:我添加了 .Where 因为 .Descendants 会递归。

于 2012-08-14T15:00:26.353 回答
2

您可以使用for语句,然后您将始终知道索引。我正在做一个Descendants()可以在 for 语句中使用的假设。

另一种可能性是在foreach.

int count = 0
foreach (var element2 in doc2.Root.Descendants())
{
    String name = element.Name.LocalName;
    String value = element.Value;

    count++;
}
于 2012-08-14T14:54:43.790 回答
1

foreach用普通循环替换你的for循环:

for (int i = 0; i < doc2.Root.Descendants().Count(); i++)
{
    String name = doc2.Root.Descendants()[i].Name.LocalName;
    String value = doc2.Root.Descendants()[i].Value;
}

然后用于i查看您是否正在阅读第一个、第二个、第三个等标签。

如果不使用外部计数器,就无法获取 foreach 枚举器的索引.. AFAIK。

这也带来了效率问题,因为每次循环迭代都必须处理 Descendants 方法两次,所以我建议在 for 循环之外保留一个表示 Descendants 的 List,然后像这样使用它:

var desecendants = doc2.Root.Descendants().ToList();
for (int i = 0; i < descendants.Count; i++)
{
    String name = descendants[i].Name.LocalName;
    String value = descendants[i].Value;
}
于 2012-08-14T14:54:05.910 回答
1

我认为你不能使用 foreach,尝试使用普通的 for 循环。

于 2012-08-14T14:54:23.133 回答
1

使用变量作为计数器并将结果放入数组中。这里的问题是,您需要提前知道数组的大小。

int i = 0;
foreach (var element in doc2.Root.Descendants()) {
     name[i] = element.Name.LocalName;
     value[i] = element.Value;
     i++;
} 

使用 aList<T>你没有这个问题

var list = new List<KeyValuePair<string,string>>();
foreach (var element in doc2.Root.Descendants()) {
     list.Append(new KeyValuePair(element.Name.LocalName, element.Value));
} 
于 2012-08-14T14:57:25.270 回答
0

要在没有计数器的情况下获取当前节点的位置(如先前的解决方案指出的那样),您需要编写一个函数来构建当前 XmlElement 的 XPath。唯一的方法是使用父节点和以前的兄弟节点从您的节点遍历文档。这样,您将能够构建准确的 XPath 以从文档中访问您的节点。这是从这里获取的样本

   public static string GetXPath_UsingPreviousSiblings(this XmlElement element)
    {
        string path = "/" + element.Name;

        XmlElement parentElement = element.ParentNode as XmlElement;
        if (parentElement != null)
        {
            // Gets the position within the parent element, based on previous siblings of the same name.
            // However, this position is irrelevant if the element is unique under its parent:
            XPathNavigator navigator = parentElement.CreateNavigator();
            int count = Convert.ToInt32(navigator.Evaluate("count(" + element.Name + ")"));
            if (count > 1) // There's more than 1 element with the same name
            {
                int position = 1;
                XmlElement previousSibling = element.PreviousSibling as XmlElement;
                while (previousSibling != null)
                {
                    if (previousSibling.Name == element.Name)
                        position++;

                    previousSibling = previousSibling.PreviousSibling as XmlElement;
                }

                path = path + "[" + position + "]";
            }

            // Climbing up to the parent elements:
            path = parentElement.GetXPath_UsingPreviousSiblings() + path;
        }

        return path;
    }

假设这确实是您真正需要的,根据文档大小,它可能是资源密集型的。如果您只需要索引,我建议您使用其他方法之一。

于 2012-08-14T15:02:09.980 回答