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 ファイルから、非常に具体的なデータを取得することだと私には思えます。ここで行うことのほとんどは、アプリケーション内のマップを表す配列に各「タイル」要素の 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 "";
            }
        }

これにより、完全な URI を使用せずに、XPath を使用して XML ドキュメントをクエリするオプションが提供されます。

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

ここでの要約は、各フレームワークには重複する機能のセットがあるということです。ただし、一部は他のものよりも専門的なジョブに使用するのに適しています。

于 2013-10-08T12:18:48.253 に答える