2

我正在构建一个简单的自上而下的基于瓷砖的 2D 游戏,并且我正在尝试解析 Tiled Map Editor(.tmx 文件)的输出。对于那些不熟悉的人,TMX 文件是 XML 文件,它使用图像中重复使用的图块层来描述游戏地图。除了解析简单的文本之外,我从来没有处理过任何事情,我想知道,对于一个相当简单的 XML 文件,使用 LINQ 是否是最合适的方法。

这是一个删节的 .tmx 文件:

<?xml version="1.0" encoding="UTF-8"?>
<map width="100" height="100" tilewidth="16" tileheight="16">
    <tileset>
        <!-- This stuff in here is mostly metadata that the map editor uses  -->
    </tileset>
    <layer name="Background" width="100" height="100">
        <data>
            <tile gid="1" />
            <tile gid="2" />
            <tile gid="3" />
            <tile gid="1" />
            <tile gid="1" />
            <tile gid="1" />
            <!-- etc... -->
        </data>
    </layer>
    <layer name="Foreground" width="100" height="100">
        <data>
            <!-- gid="0" means don't load a tile there. It should be an empty cell for that layer (and the layers beneath this are visible) -->
            <tile gid="0" />
            <tile gid="4" />
            <!-- etc. -->
        </data>
    </layer>
    <!-- More layers.... -->
</map>

如您所见,它相当简单(请注意,每一层中的每个图块 (100x100) 都有一个“图块”元素)。现在在我看来,LINQ 的目的是从可能非常大且几乎类似于数据库的 xml 文件中获取非常具体的数据,您并不需要整个文件。大多数情况下,我将在这里执行的操作是将每个“tile”元素的 gid 插入到一个数组中,该数组表示我的应用程序中的地图。

这是我处理图层的代码:

public void AddLayer(XElement layerElement) {
    TileMapLayer layer = new TileMapLayer(Convert.ToInt32(layerElement.Attribute("width")), Convert.ToInt32(layerElement.Attribute("height")));
    layer.Name = (string)layerElement.Attribute("name");
    layer.Opacity = Convert.ToDouble(layerElement.Attribute("opacity"));
    layer.Visible = Convert.ToInt32(layerElement.Attribute("visible")) == 1;
    if (layerElement.HasElements)
    {
        XElement data = layerElement.Element("data");
        foreach (XElement tile in data.Elements())
        {
            layer.NextTile(Convert.ToInt32(tile.Attribute("gid")));
        }
    }
    this.layers.Add(layer);
}

为了让我的问题更简洁:当我正在经历并且我关心每条数据时(即我正在迭代并按顺序获取每个节点的所有子元素的数据),使用 LINQ to XML 是否可以为我提供任何好处?就像 LINQ to XML 库的性能更好吗?我对 LINQ 的不熟悉是否会阻止我看到一种有效的方式来做我想做的事?等等?或者我真的应该使用不同的 XML 实用程序吗?

4

1 回答 1

3

对于简单地检索和更新数据,LINQ to XML 似乎是一种用于 XML 解析的方钉/圆孔解决方案。XElement 当然可以递归迭代,但我发现 XPath 查询更加简洁易读。

我发现 LINQ to XML 非常有用的地方在于处理文档命名空间。.NET 提供的其他框架并没有以优雅的方式处理此问题。根据http://msdn.microsoft.com/en-us/library/ecf3e2k0.aspx

更改节点的前缀不会更改其名称空间。命名空间只能在创建节点时设置。当您持久化树时,可能会持久化新的命名空间属性以满足您设置的前缀。如果无法创建新命名空间,则更改前缀以使节点保留其本地名称和命名空间。

当然,这是一个深奥的要求,但我发现 LINQ to XML 在为 XPath 查询准备命名空间管理器时也很有用。

public XmlNamespaceManager NamespaceManager { get; set; }
public XPathNavigator Navigator { get; set; }
public SuperDuperXMLQueryingClass(System.IO.Stream stream)
        {
            var namespaces = RetrieveNameSpaceMapFromXml(XDocument.Load(stream).Root);
            Navigator = new XPathDocument(stream).CreateNavigator();
            NamespaceManager = new XmlNamespaceManager(Navigator.NameTable);

            foreach (var t in namespaces)
            {
                NamespaceManager.AddNamespace(t.Key, t.Value.NamespaceName);
            }
        }
// LINQ to XML mostly used here.
private static Dictionary<string, XNamespace> RetrieveNamespaceMapFromXDocumentRoot(XElement root)
        {
            if (root == null)
            { throw new ArgumentNullException("root"); }

            return root.Attributes().Where(a => a.IsNamespaceDeclaration)
                                     .GroupBy(a => (
                                                        a.Name.Namespace == XNamespace.None ? String.Empty : a.Name.LocalName),
                                                        a => XNamespace.Get(a.Value)
                                                    )
                                     .Where(g => g.Key != string.Empty)
                                     .ToDictionary(g => g.Key, g => g.First());
        }
public string DeliverFirstValueFromXPathQuery(string qry)
        {
            try
            {
                var iter = QueryXPathNavigatorUsingShortNamespaces(qry).GetEnumerator();
                iter.MoveNext();
                return iter.Current == null ? string.Empty : iter.Current.ToString();
            }
            catch (InvalidOperationException ex)
            {
                return "";
            }
        }

这使您可以选择使用 XPath 来查询您的 XML 文档,而不必使用完整的 URI。

//For Example
DeliverFirstValueFromXPathQuery("/ns0:MyRoot/ns1:MySub/nsn:ValueHolder");

这里的总结是每个框架都有一些重叠的功能;然而,有些更适合用于专业工作。

于 2013-10-08T12:18:48.253 回答