【问题标题】:Get all child element values of specific node using XPath使用 XPath 获取特定节点的所有子元素值
【发布时间】:2023-03-26 17:14:02
【问题描述】:

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

这是 XML:

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

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

XPathDocument missionDoc = new XPathDocument(objectivesPath + "MissionObjectives" + chosenTheme + ".xml");

XPathNavigator nav = missionDoc.CreateNavigator();

foreach (Scenery scenery in world.currentWorld)
{
    int sceneryType = scenery.type;

    XPathExpression expr = nav.Compile($"MissionObjectives/Theme/SceneryType[text()='{sceneryType}']//Objective");

    XPathNodeIterator iterator = nav.Select(expr);

    while (iterator.MoveNext())
    {
        XPathNavigator nav2 = iterator.Current.Clone();
        compatibleObjectivesList.Add(nav2.Value);
    }
}

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

为任何帮助干杯!

【问题讨论】:

    标签: c# xml xpath


    【解决方案1】:

    使用 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样本

    【讨论】:

    • 太好了,这(加上一些厚颜无耻的循环)正是我所需要的!谢谢。
    【解决方案2】:

    首先,您的 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
            {
    
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-06
      • 1970-01-01
      • 1970-01-01
      • 2021-07-16
      • 2017-02-24
      • 1970-01-01
      • 2011-05-06
      相关资源
      最近更新 更多