如何获取xml节点的兄弟节点

时间:2022-11-26 23:44:30

I have an xml file as below

我有一个xml文件,如下所示

<Games>
   <Game>
      <name>Tzoker</name>
      <file>tzoker1</file>
   </Game>
   <Game>
      <file>lotto770</file>
   </Game>
   <Game>
      <name>Proto</name>
      <file>proto220</file>
   </Game>
</Games>

I want to get the values of name and file items for every Game node. It is easy by using this query.

我想获取每个Game节点的名称和文件项的值。使用此查询很容易。

string query = String.Format("//Games/Game");
 XmlNodeList elements1 = xml.SelectNodes(query);
 foreach (XmlNode xn in elements1)
 {
   s1 = xn["name"].InnerText;
   s2 = xn["file"].InnerText;
 }

The problem is that there are some nodes that they don't have the name item. So the code above doesn't work. I have solved the problem by using the following code

问题是有些节点没有名称项。所以上面的代码不起作用。我已使用以下代码解决了该问题

string query = String.Format("//Games/Game/name");
XmlNodeList elements1 = xml.SelectNodes(query);
foreach (XmlNode xn in elements1)
{
  s1 = xn.InnerText;
  string query1 = String.Format("//Games/Game[name='{0}']/file", s1);
  XmlNodeList elements2 = xml.SelectNodes(query1);
  foreach (XmlNode xn2 in elements2)
  {
    s2 = xn2.InnerText;
  }
}

The problem is that there is a case that two or more nodes have the same name value. So, the s2 variable will get the file value of the last node that the loop finds. So, I would like to find a way to get the sibling file value of the current name item. How could I do it? I try do move to the parent node of the current node and then to move to the file item but without success by using the following code.

问题是存在两个或更多节点具有相同名称值的情况。因此,s2变量将获取循环找到的最后一个节点的文件值。所以,我想找到一种方法来获取当前名称项的兄弟文件值。我怎么能这样做?我尝试移动到当前节点的父节点,然后移动到文件项但是没有成功使用以下代码。

string query = String.Format("//Games/Game/name");
XmlNodeList elements1 = xml.SelectNodes(query);
foreach (XmlNode xn in elements1)
{
   s1 = xn.InnerText;
   string query1 = String.Format("../file");
   XmlNodeList elements2 = xml.SelectNodes(query1);
   foreach (XmlNode xn2 in elements2)
   {
     s2 = xn2.InnerText;
   }
}

I hope there is a solution.

我希望有一个解决方案。

2 个解决方案

#1


0  

You can use Game[name] to filter Game elements to those with child element name. This is possible because child:: is the default axes which will be implied when no explicit axes mentioned. Extending this further to check for child element file as well, would be as simple as Game[name and file] :

您可以使用Game [name]将Game元素过滤为具有子元素名称的元素。这是可能的,因为child ::是默认的轴,当没有提到明确的轴时将隐含这些轴。进一步扩展以检查子元素文件,就像Game [name and file]一样简单:

string query = String.Format("//Games/Game[name]");
XmlNodeList elements1 = xml.SelectNodes(query);
foreach (XmlNode xn in elements1)
{
   s1 = xn["name"].InnerText;
   s2 = xn["file"].InnerText;
}

Now to answer your question literally, you can use following-sibling:: axes to get sibling element that follows current context element. So, given the context element is name, you can do following-sibling::file to return the sibling file element.

现在,从字面上回答你的问题,你可以使用follow-sibling :: axes来获取当前上下文元素之后的兄弟元素。因此,给定context元素是name,您可以执行follow-sibling :: file来返回兄弟文件元素。


Your attempt which uses ../file should also work. The only problem was, that your code executes that XPath on xml, the XmlDocument, instead of executing it on current name element :

您使用../file的尝试也应该有效。唯一的问题是,您的代码在xml上执行XPath,即XmlDocument,而不是在当前名称元素上执行它:

XmlNodeList elements2 = xn.SelectNodes("../file");

#2


0  

If I understand you correctly you want to find all games that have a name. You can do that using XPath. Here is a solution that uses LINQ to XML. I find that easier to work with than XmlDocument:

如果我理解正确你想找到所有有名字的游戏。你可以使用XPath做到这一点。这是一个使用LINQ to XML的解决方案。我发现比XmlDocument更容易使用:

var xDocument = XDocument.Parse(xml);
var games = xDocument
  .Root
  .XPathSelectElements("Game[child::name]")
  .Select(
    gameElement => new {
      Name = gameElement.Element("name").Value,
      File = gameElement.Element("file").Value
    }
  );

The XPath to select all <Game> elements that have a <name> child element is Game[child::name].

选择具有 子元素的所有 元素的XPath是Game [child :: name]。

#1


0  

You can use Game[name] to filter Game elements to those with child element name. This is possible because child:: is the default axes which will be implied when no explicit axes mentioned. Extending this further to check for child element file as well, would be as simple as Game[name and file] :

您可以使用Game [name]将Game元素过滤为具有子元素名称的元素。这是可能的,因为child ::是默认的轴,当没有提到明确的轴时将隐含这些轴。进一步扩展以检查子元素文件,就像Game [name and file]一样简单:

string query = String.Format("//Games/Game[name]");
XmlNodeList elements1 = xml.SelectNodes(query);
foreach (XmlNode xn in elements1)
{
   s1 = xn["name"].InnerText;
   s2 = xn["file"].InnerText;
}

Now to answer your question literally, you can use following-sibling:: axes to get sibling element that follows current context element. So, given the context element is name, you can do following-sibling::file to return the sibling file element.

现在,从字面上回答你的问题,你可以使用follow-sibling :: axes来获取当前上下文元素之后的兄弟元素。因此,给定context元素是name,您可以执行follow-sibling :: file来返回兄弟文件元素。


Your attempt which uses ../file should also work. The only problem was, that your code executes that XPath on xml, the XmlDocument, instead of executing it on current name element :

您使用../file的尝试也应该有效。唯一的问题是,您的代码在xml上执行XPath,即XmlDocument,而不是在当前名称元素上执行它:

XmlNodeList elements2 = xn.SelectNodes("../file");

#2


0  

If I understand you correctly you want to find all games that have a name. You can do that using XPath. Here is a solution that uses LINQ to XML. I find that easier to work with than XmlDocument:

如果我理解正确你想找到所有有名字的游戏。你可以使用XPath做到这一点。这是一个使用LINQ to XML的解决方案。我发现比XmlDocument更容易使用:

var xDocument = XDocument.Parse(xml);
var games = xDocument
  .Root
  .XPathSelectElements("Game[child::name]")
  .Select(
    gameElement => new {
      Name = gameElement.Element("name").Value,
      File = gameElement.Element("file").Value
    }
  );

The XPath to select all <Game> elements that have a <name> child element is Game[child::name].

选择具有 子元素的所有 元素的XPath是Game [child :: name]。