65.9K
CodeProject 正在变化。 阅读更多。
Home

XLINQ to WoW Realm Status

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.83/5 (9投票s)

2007年11月2日

CPOL

8分钟阅读

viewsIcon

51636

downloadIcon

95

本文将解释并演示如何使用XLINQ(LINQ to XML)来获取WoW服务器状态。

引言

如今有很多人在玩《魔兽世界》(确切地说是900万+)。所以我认为展示如何将许多人生活中的两个爱好结合起来是合适的,那就是游戏和编程。

背景

XML是一种开放的数据格式,很多人可以在任何平台上使用它,难怪大公司依赖它来存储和显示数据。一些公司/个人使用它来保存应用程序设置、博客文章以及许多其他内容。其中一个例子就是暴雪使用它来显示WoW服务器状态。本文将展示如何利用这种开放的数据格式以及.NET 3.5的全新XML to LINQ框架,将其用于任何应用程序,无论是Web还是可部署的可执行文件。

请注意,在撰写本文时,.NET 3.5和Visual Studio 2008均处于Beta 2阶段,而《魔兽世界》的订阅用户已超过900万。

Using the Code

理解数据背后的故事

如果我们要做任何查询,我们就需要数据。所以,首先,我们将看一下暴雪的WoW服务器状态XML页面。

如果您使用的是现代网页浏览器,您将看不到任何XML,您应该会看到一个格式适中的页面,其中包含每个服务器的状态、类型和流行度。现在,如果您想知道为什么您看不到任何XML,这是一个好问题。这个页面,就像许多HTML页面一样,只是带有附加样式表的XML。如果您熟悉XHTML,您会知道它是一个HTML的混合体,因为它符合XML规范。与HTML页面非常相似,它附加了一个样式表。要看到这一点,请右键单击页面并选择“查看源代码”。

您应该会看到这个

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="realmstatus.xsl"?>

第一行是XML声明,第二行是附加到数据的样式表。我将不再深入介绍XML/XML样式表的工作原理,主要是因为这不是本文的重点。我解释这一点是为了帮助您理解为什么XML文件中会出现样式。

理解数据

如果您继续查看XML的源代码,您会看到一个类似这样的行,代表每个服务器

<r n="Aegwynn" t="2" s="1" l="1"/>

暴雪创建了一些高度优化的XML,其属性名称非常非常短。我猜这会让下载速度更快。现在,这些属性中的每一个都代表某些东西。让我们试着弄清楚它们的含义。

  • N:在我看来很明显,这是服务器的名称。
  • T:T?那会是什么呢?有几种方法可以弄清楚,要么通过查看格式化的XML并将其与原始XML进行交叉引用,要么查看样式表。通过查看样式表,我们看到这个属性代表服务器的Type(类型)。1 = Normal(正常),2 = PvP,3 = RP(角色扮演),4 = RPPvP。
  • S:通过查看样式表,我们可以看到S代表Status(状态),它代表服务器的状态。1 = Up(在线),其他所有值 = Down(离线)。
  • L:如果您查看样式表的底部,您可以看到L代表Population(人口)(或Load(负载))。1 = Low(低),2 = Normal(正常),3 = High(高),4 = Max (Queued)(最大(排队中))。

如果我们看一下上面例子中的那一行,我们可以看到服务器是Aegwynn,一个PvP服务器,它在线且人口较少。很简单,不是吗?

在代码中使用数据

现在我们已经了解了我们要处理的数据。接下来,我们想在代码的上下文中能够使用它。这实际上非常简单,使用XLINQ(LINQ to XML)。

为了本文的目的,我将使用一个Windows Forms应用程序,但您可以随时在任何上下文中(ASP.NET、WCF、WPF等)使用此代码。

首先,启动Visual Studio 2008并创建一个Windows Forms应用程序。向项目中添加一个名为RealmStatus的类。这个类基本上将成为服务器状态XML中每个服务器XML元素的包装器。为了使这个包装器更用户友好,让我们创建一些枚举。

public enum RealmPopulation
{
    Low = 1,
    Normal,
    High,
    Max
}

public enum RealmType
{
    Normal = 1,
    PvP,
    RP,
    RPPvP
}

这些枚举将在代码和数据的可视化呈现方面都对我们有所帮助。接下来,我们需要一个类来包装整个服务器状态元素。为此,我们将使用.NET的全新自动属性功能来创建一个类。

public class RealmStatus
{
    public string Name { get; set; }
    public RealmPopulation Population { get; set; }
    public RealmType Type { get; set; }
    public bool Up { get; set; }
}

现在我们有了代表WoW服务器状态的类,让我们继续获取XML并对其进行查询。

添加另一个类并将其命名为WowRealms。在继续之前,我们需要在类的顶部添加一个using语句。

using System.Xml.Linq;

接下来是我们的WowRealms类,我将其设为静态,因为它不应该持有状态。

public static class WowRealms
{
}

现在我们需要创建一个方法,从我们之前使用的URL获取XDocument。使用XLINQ,这实际上非常简单。

public static XDocument GetDocument()
{
    return XDocument.Load("http://www.worldofwarcraft.com/realmstatus/status.xml");
}

是的,这真的是我们要做的所有事情,以获得我们之前看到的XML数据的有效XDocument项。现在,有趣的开始了!

让我们创建一个方法,允许我们从服务器名称检索RealmStatus对象。为此,我们需要使用LINQ to XML来查询元素列表并返回一个新的RealmStatus对象。创建一个名为GetRealmStatusByName的方法,该方法将返回一个RealmStatus对象。

public static RealmStatus GetRealmStatusByName(string realmName)
{
    XDocument document = GetDocument();
    RealmStatus realmStatus = 
    (from s in document..Element("page").Element("rs").Elements("r")
                               where s.Attribute("n").Value == realmName
                               select new RealmStatus()
                               {
                                   Name = s.Attribute("n").Value,
                                   Population = (RealmPopulation)Enum.Parse
                (typeof(RealmPopulation), s.Attribute("l").Value),
                                   Type = (RealmType)Enum.Parse(typeof(RealmType), 
                    s.Attribute("t").Value),
                                   Up = s.Attribute("s").Value == "1"
                               }).SingleOrDefault();
    return realmStatus;
}

最后,是一个内容丰富的<>方法。乍一看,这个方法可能看起来相当混乱,但老实说,它真的很简单。让我们来剖析一下这个方法。

XDocument document = GetDocument();

这真的是不言自明的,我们只是从status.xml文件中获取XML数据。

RealmStatus realmStatus = (from s in document.Element("rs").Elements("r")
                           where s.Attribute("n").Value == realmName

前两行是我们LINQ查询的开始。在第一行,我们通过获取“rs”元素中的所有“r”元素来设置查询。为了帮助可视化,让我们看一下XML文件。

<rs>
    <r n="Aegwynn" t="2" s="1" l="1"/>
    <r n="Aerie Peak" t="1" s="1" l="3"/>
    <r n="Agamaggan" t="2" s="1" l="1"/>
    <r n="Aggramar" t="1" s="1" l="3"/>
    ...
</rs>

如您所见,我们有根元素<rs>和子元素<r>。在LINQ查询的第二行,我们添加了一个where表达式,它只查找名称与方法参数传递的服务器匹配的服务器。为了做到这一点,我们正在获取“r”元素的“n”属性。

select new RealmStatus()
{
   Name = s.Attribute("n").Value,
   Population = (RealmPopulation)Enum.Parse(typeof(RealmPopulation), 
        s.Attribute("l").Value),
   Type = (RealmType)Enum.Parse(typeof(RealmType), s.Attribute("t").Value),
   Up = s.Attribute("s").Value == "1"
}).SingleOrDefault();

LINQ查询的这一部分就像任何正常SQL查询中的SELECT语句一样。我们将从每个元素中获取属性,并使用.NET对象初始化功能将属性值从我们的查询中插入。虽然这看起来我们只想获取一个服务器,但如果我们的查询返回的结果多于一个,此操作实际上将对返回的每个元素执行。查询的最后一行是对SingleOrDefault()方法的调用,因为我们知道服务器名称只能有一个结果。

return realmStatus;

……并返回我们的结果!请注意——如果给定服务器名称没有结果,它将返回null

现在是时候测试我们的代码了!为此,让我们创建一个简单的界面,允许用户输入服务器名称进行搜索,并将一些输出显示给用户。我创建了一个非常基本的界面,看起来是这样的

TextBox下方还有一个Label,我们可以用它来显示一些输出,您看不到它,因为它将其Text属性设置为None。现在我们已经创建了UI和代码基础,让我们为ButtonClick事件添加一个事件处理程序,并向用户输出一些数据。

这是我在ButtonClick事件处理程序中使用的代码

private void SearchButton_Click(object sender, EventArgs e)
{
    string realmName = RealmNameTextBox.Text;
    RealmStatus realmStatus = WowRealms.GetRealmStatusByName(realmName);
    if (realmStatus == null)
    {
        OutputLabel.Text = 
          string.Format("No realm with name {0} was found", realmName);
    }
    else
    {
        string serverStatus = string.Empty;
        if (realmStatus.Up)
        {
            serverStatus = "Up";
        }
        else
        {
            serverStatus = "Down";
        }
        OutputLabel.Text = string.Format("{0} ({1}) has a population of {2} and is {3}", 
    realmStatus.Name, realmStatus.Type, realmStatus.Population, serverStatus);
    }
}

这段代码非常简单。您会注意到包装它使我们能够轻松使用它,以及我们的表单代码多么整洁。现在,我们有了一个有效的数据层和表示层……少说废话,让我们试试吧。

太棒了,它奏效了!

好了,我希望这能帮助那些想学习新技术的人,并且也许能引起一些游戏玩家的兴趣,让他们尝试编程。正如您所见,这段代码非常灵活且易于使用,不仅在Windows Forms中,而且在WPF、WCF、ASP.NET,甚至Vista小工具中!

我展示了.NET 3.5的一些全新技术,这些技术使当今的开发人员更具生产力和效率。这些功能包括:Base Class Library中的XLINQ、自动属性和对象初始化。这仅仅是冰山一角,我鼓励所有阅读本文的读者去购买/下载Visual Studio 2008/.NET 3.5 Express版本,并且不要局限于自己。

玩得开心!

关注点

  • 在撰写本文时,Visual Studio 2008和.NET Framework 3.5都处于Beta 2阶段,而暴雪的《魔兽世界》拥有超过900万订阅用户。

历史

  • 2007年11月2日:初始帖子。
  • 2008年9月19日:编辑以反映XML更新,感谢btlife
© . All rights reserved.