在c#中使用XmlDocument类读取结束标记

时间:2013-04-15 19:05:09

标签: c# xml xml-parsing

我有没有办法阅读结束标签,例如使用XMLDocument类。由于某些限制,我无法使用XmlREader或XmlTextReader。在MSDN中,提到我只能将XmlNodeType.EndElement用于XMLReader MSDN link。我的代码是这样的:

 XmlDocument doc = functionWhichReturnsXmlDoc();
 XmlNodeList nodes =textDoc.ChildNodes;
 foreach (XmlNode node in nodes)
{
 switch (node.NodeType)
   {
     case XmlNodeType.Element:
     XmlNodeList nodes =textDoc.ChildNodes;
           switch (node.NodeType)
            {
                case XmlNodeType.Element:
                    //do something
                case XmlNodeType.Text:
                    //do something
                case XmlNodeType.EndElement:
                // THIS EVER EXECUTES   
            }
         }
}

我的XML文件“

<Text >
<environment>
    <Tempratue>
        <element id="COLD">Cold</element>
        <element id="MILd">Mild</element>
        <element id="HOT">Hot</element>
    </Tempratue>
        <element id = "Windy">true</element>
</environment>
<dish>
<element id = "dish1">1111</element>
<element id = "dish2">2222</element>
</dish>

</Text>

我想把输出作为字符串列表: -

/Text/Environment/Temprature/COLD
/Text/Environment/Temprature/MILD
/Text/Environment/Temprature/HOT
/Text/Environment/Windy
/Text/dish/dish1
/Text/dish/dish2

提前致谢。

- AAT

2 个答案:

答案 0 :(得分:4)

我不确定你是如何设想你的算法工作的,但我很确定你的方法是错误的。这是一种可以提供您所描述的路径列表的方法:

internal static List<string> BuildPaths(XmlDocument doc)
{
    List<string> paths = new List<string>();

    BuildPaths(doc.DocumentElement, paths);

    return paths;
}

private static void BuildPaths(XmlNode node, List<string> paths, string prefix = "/")
{
    if (node.Name == "element")
    {
        // end case - elements named "element"
        paths.Add(prefix + node.Attributes["id"].Value);
    }
    else
    {
        // iterate through child nodes that are either not named element or that 
        // have an attribute named "id" (i.e. skip elements named "element" that 
        // lack an id attribute)
        foreach (XmlNode child in node.SelectNodes("*[not(self::element) or @id]"))
        {
            BuildPaths(child, paths, prefix + node.Name + "/");
        }
    }
}

在样本XML上运行此操作时,结果是以下字符串的列表:

/Text/environment/Tempratue/COLD
/Text/environment/Tempratue/MILd
/Text/environment/Tempratue/HOT
/Text/environment/Windy
/Text/dish/dish1
/Text/dish/dish2

这是一种我更喜欢的方法,因为它遵循函数式编程原则。在这种情况下,上面的第一个BuildPaths()方法将是不必要的;您可以将XmlDocument直接传递给此方法:

private static List<string> BuildPaths(XmlNode node, string prefix = "/")
{
    // Get child node if current node is the root
    if (node.NodeType == XmlNodeType.Document) { node = node.FirstChild; }

    if (node.Name == "element")
    {
        return new List<string> { prefix + node.Attributes["id"].Value };
    }
    else
    {
        return node.SelectNodes("*[not(self::element) or @id]")
                   .OfType<XmlNode>()
                   .Select(n => BuildPaths(n, prefix + node.Name + "/"))
                   .SelectMany(l => l)
                   .ToList();
    }
}

答案 1 :(得分:0)

不是试图检测EndElement节点,而是反向工作。 以您知道自己身份的方式存储您的路径信息,然后您可以按照从外到内的顺序打印出路径。

我会使用List<string>StringBuilder执行此操作,列表会更容易操作。输入新的子节点组时,只需存储要打印的字符串,并根据需要添加节点名称或属性值,然后编写正确解释列表的打印输出函数。