【问题标题】:Accessing XElement with specific value使用特定值访问 XElement
【发布时间】:2015-03-05 22:00:06
【问题描述】:

我正在尝试将我的战舰游戏保存为 XML,到目前为止它进展顺利。我在 XML 文件中保存的是玩家姓名、船只和未命中的坐标。

船的 ID 属性是知道哪个船坐标构成了整艘船。接下来是通过将属性添加到正确的元素来标记每艘被击中的船,我知道通过它的值可以获得什么元素。

但我不知道如何获得它。我所发现的只是如何通过其name 和所有具有该名称的元素来获取XElement

<?xml version="1.0" encoding="UTF-8" ?>
<Players>
  <Playerboard>
    <Name>Player</Name>
    <Ships>
      <ship id="1213">12_13</ship>
      <ship id="1213">12_14</ship>
      <ship id="1211">12_11</ship>
      <ship id="1211">12_12</ship>
    </Ships>
    <Misses>
      <Miss>3_9</Miss>
      <Miss>9_12</Miss>
      <Miss>10_12</Miss>
    </Misses>
  </Playerboard>
  <Computerboard>
    <Name>AI</Name>
    <Ships>
      <ship id="1010">10_10</ship>
      <ship id="1010">10_11</ship>
      <ship id="1010">10_12</ship>
      <ship id="1010">10_13</ship>
      <ship id="11">1_1</ship>
      <ship id="11">2_1</ship>
    </Ships> 
    <Misses>
      <Miss>0_2</Miss>
      <Miss>0_3</Miss>
      <Miss>1_3</Miss>
    </Misses>
  </Computerboard>
</Players>

这是我试图获取正确元素的结果,但这是行不通的。我下面示例中的“k”一直是空的。

XElement e = xelement.Element("Playerboard");
var ships = from s in e.Elements("Ships")            
                        where (string)s.Element("ship") == x + "_" +y
                        select s;

foreach (XElement k in ships) 
{ 
   Console.WriteLine(k);
}

例如,我想为船添加一个值为 12_12 的属性,我该怎么做?

【问题讨论】:

  • 欢迎来到 StackOverflow!希望在使用 C# 管理 XML 方面有更多知识的人出现并为您提供答案,但我可能建议在将其写入控制台时在 k 上添加 .ToString()Console.WriteLine(k.ToString());
  • 签出此链接stackoverflow.com/questions/10844374/… 以及谷歌如何使用XPath
  • @kehrk: Console.WriteLine 会为你做这件事。
  • 只是一个想法,也许我遗漏了一些东西 - 如果您自己创建 XML,为什么不首先创建完整的呢?为什么创建不完整然后编辑它?
  • stackoverflow.com/questions/10844374/… 只告诉我我不想做什么。他们通过元素的名称而不是它的值来访问元素。和@vesan你错过了一些是的。它应该是一个战舰游戏,这个 xml 文件代表了游戏的状态。我要添加的属性是在击中船时添加的。这就是为什么我不能从一开始就添加它。

标签: c# xml linq linq-to-xml xelement


【解决方案1】:

这对我来说很好用:

var doc = XDocument.Parse(xml);

var elements =
    doc
    .Root                       //Ignore the root
    .Element("Playerboard")     //The Playerboard element.
    .Element("Ships")           //There's only one Ships element.
    .Elements("ship")           //Get all the ship elements from Ships.
    .Where(ship => ship.Value == "12_12");  //.Value is a little more explicit but you
                                            //want strings anyway.

foreach (var element in elements)
{
    Console.WriteLine(element);
    element.Add(new XAttribute("Name", "Value")); //Adding your new attribute.
    Console.WriteLine(element); 
}

我使用 lambda 语法是因为我更喜欢它(抱歉,它只是让我在做什么更清楚)。

如果您只希望有一个ship 元素与给定值匹配,您也可以在末尾使用.Single() 来避免收集。

【讨论】:

  • 对我来说看起来不错,虽然它不做任何检查是否存在 - 如果任何中间节点不存在,你最终会得到NullReferenceException
  • @vesan 我通常避免对堆栈溢出答案进行错误检查,这样可以防止它们变得太长。如果 OP 知道他们必须处理丢失部分的可能性,我相信他们可以解决。
【解决方案2】:

你也可以这样做:

   int x = 12, y = 12;
   var doc =  XDocument.Load("[path of your xml]");

   //Finding the playerboard, by your structure I suppose you have one
   var playerBoard= doc.Descendants("Playerboard").FirstOrDefault();

  var ship = playerBoard.Element("Ships").Elements("ship").FirstOrDefault(e => e.Value == x + "_" + y);

  //Adding an attribute to the ship
  ship.Add(new XAttribute("Foo", "Boo")); 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多