使用XPath获取特定节点的所有子元素值

时间:2017-07-11 14:04:16

标签: c# xml xpath

我正在使用XPath从XML文档中读取元素。具体来说,我想返回任何元素的值,该元素是指定元素的子元素(这里指定的元素是<SceneryType>,并且这些元素具有单位数值。所以我想返回{{的所有子元素1}}例如。

这是XML:

<SceneryType> 1

我尝试了各种方法来获取这些子元素,但我无法理解。我的//表达式的目标部分只返回从它看起来的根,但是迭代器没有运行,这似乎很奇怪,如果表达式返回所有元素的节点列表,它不应该遍历每个元素吗?

<MissionObjectives>
<Theme themeName="Gothic">
    <SceneryType>
    1
        <Objective>
        Do a river thing.
        </Objective>
        <Objective>
        Get all men to the other side of the river.
        </Objective>
    </SceneryType>
    <SceneryType>
    2
        <Objective>
        Climb some trees!
        </Objective>
        <Objective>
        Shoot the tree!
        </Objective>
    </SceneryType>
</Theme>

我已经尝试通过Stack Overflow查找类似的问题,但我似乎无法找到适用于XPath的任何内容。我不能为此使用LINQ to XML。知道如何返回各种“目标”节点的所有值吗?

为任何帮助干杯!

2 个答案:

答案 0 :(得分:0)

例如,您的xml数据在搜索元素的文本节点中具有回车符,换行符和空格。请记住,XML节点可以是元素,属性或文本(以及其他节点类型)。下面的解决方案有点在“长手”的一面,也许有点“hacky”,但它应该工作。我不确定你是否想要子元素文本数据或整个子元素,但我只返回子文本节点数据(没有回车符和换行符)。此外,尽管此解决方案最严格意义上不使用LINQ to XML,但它确实使用了一个LINQ表达式。

    private List<string> getSceneryTypeObjectiveTextList(string xml, int sceneryTypeId, string xpath = "/MissionObjectives/Theme/SceneryType")
    {
        List<string> result = null;
        XmlDocument doc = null;
        XmlNodeList sceneryTypeNodes = null;

        try
        {
            doc = new XmlDocument();
            doc.LoadXml(xml);

            sceneryTypeNodes = doc.SelectNodes(xpath);

            if (sceneryTypeNodes != null)
            {
                if (sceneryTypeNodes.Count > 0)
                {
                    foreach (XmlNode sceneryTypeNode in sceneryTypeNodes)
                    {
                        if (sceneryTypeNode.HasChildNodes)
                        {
                            var textNode = from XmlNode n in sceneryTypeNode.ChildNodes
                                           where (n.NodeType == XmlNodeType.Text && n.Value.Replace("\r", "").Replace("\n", "").Replace(" ", "") == sceneryTypeId.ToString())
                                           select n;

                            if (textNode.Count() > 0)
                            {
                                XmlNodeList objectiveNodes = sceneryTypeNode.SelectNodes("Objective");

                                if (objectiveNodes != null)
                                {
                                    result = new List<string>(objectiveNodes.Count);

                                    foreach (XmlNode objectiveNode in objectiveNodes)
                                    {
                                        result.Add(objectiveNode.InnerText.Replace("\r", "").Replace("\n", "").Trim());
                                    }

                                    // Could break out of the iteration, here, if we know that SceneryType is always unique (i.e. - no duplicates in Element text node)
                                }
                            }
                        }
                    }
                }
            }

        }
        catch (Exception ex)
        {
            // Handle error
        }
        finally
        {

        }

        return result;
    }


    private sampleCall(string filePath, int sceneryTypeId)
    {
        List<string> compatibleObjectivesList = null;

        try
        {
            compatibleObjectivesList = getSceneryTypeObjectiveTextList(File.ReadAllText(filePath), sceneryTypeId);
        }
        catch (Exception ex)
        {
    // Handle error
        }
        finally
        {

        }
    }

答案 1 :(得分:0)

使用XDocument简单得多:

var doc = XDocument.Load(objectivesPath + "MissionObjectives" + chosenTheme + ".xml");

获取所有第一个SceneryType子节点:

var node = doc.XPathSelectElement("//MissionObjectives/Theme/SceneryType[1]"); 

获取第二个目标节点:

var node = doc.XPathSelectElement("//MissionObjectives/Theme/SceneryType/Objective[2]");

更多xpath个样本