XML文档中的相对引用

时间:2012-08-26 17:35:03

标签: c# xml linq-to-xml

我试图从XML文档中提取数据,这些文档似乎使用了这样的相对引用:

<action>
  <topic reference="../../action[110]/topic"/>
  <context reference="../../../../../../../../../../../../../contexts/items/context[2]"/>
</action>

两个问题:

  1. 这是正常的还是常见的?
  2. 有没有办法用linq处理XML / XDocument或者我需要手动遍历文档树?

  3. 编辑:

    为了澄清,引用是指同一XML文档中的其他节点。上面的context节点引用了一个上下文列表,并说要在索引2处得到一个。

    topic节点让我更加担心,因为它引用了某个其他操作的主题,而后者又可以引用主题列表。如果没有发生这种情况,我会在缓存中加载上下文和主题列表并以这种方式查找它们。

2 个答案:

答案 0 :(得分:0)

您可以使用XPATH Query提取节点,效率非常高。

步骤1:将XML加载到XMLDocument中 第2步:使用node.SelectNodes("//*[reference]")
第3步:之后,您可以遍历XML节点。

答案 1 :(得分:0)

我最终手动遍历树。但是使用扩展方法,这一切都很好而且不受影响。如果它可能在将来帮助任何人,这就是我为了我的用例而拼凑的东西:

public static XElement GetRelativeNode(this XAttribute attribute)
    {
        return attribute.Parent.GetRelativeNode(attribute.Value);
    }

    public static string GetRelativeNode(this XElement node, string pathReference)
    {
        if (!pathReference.Contains("..")) return node; // Not relative reference

        var parts = pathReference.Split(new string[] { "/"}, StringSplitOptions.RemoveEmptyEntries);
        XElement current = node;
        foreach (var part in parts)
        {
            if (string.IsNullOrEmpty(part)) continue;
            if (part == "..")
            {
                current = current.Parent;
            } 
            else
            {
                if (part.Contains("["))
                {
                    var opening = part.IndexOf("[");
                    var targetNodeName = part.Substring(0, opening);
                    var ending = part.IndexOf("]");
                    var nodeIndex = int.Parse(part.Substring(opening + 1, ending - opening - 1));

                    current = current.Descendants(targetNodeName).Skip(nodeIndex-1).First();
                } 
                else
                {
                    current = current.Element(part);    
                }

            }
        }

        return current;
    }

然后你会像这样使用它(itemXElement):

item.Element("topic").Attribute("reference").GetRelativeNode().Value