我如何知道XML标记的索引

时间:2012-08-14 14:49:15

标签: c# linq

如何获取当前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>标签,还是第二个或第三个......

6 个答案:

答案 0 :(得分: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会递归。

答案 1 :(得分: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++;
}

答案 2 :(得分: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方法两次,所以我建议保持一个List代表for循环之外的Descendants,然后像这样使用它:

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;
}

答案 3 :(得分:1)

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

答案 4 :(得分:1)

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

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

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

var list = new List<KeyValuePair<string,string>>();
foreach (var element in doc2.Root.Descendants()) {
     list.Append(new KeyValuePair(element.Name.LocalName, element.Value));
} 

答案 5 :(得分:0)

要获得当前节点的位置而不使用计数器(如前面的解决方案所指出的那样),您需要编写一个函数来构建当前XmlElement的XPath。唯一的方法是使用父节点和以前的兄弟节点从节点遍历文档。这样,您就可以构建精确的XPath来从文档访问您的节点。这是一个取自here

的样本
   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;
    }

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