1

次のような XML があります (非常に単純化されています)。

<?xml version="1.0"?>
<example>
    <shortcuts>
        <shortcut name="shortcut1">
            <property name="name1" value="value1" />
            <property name="name2" value="value2" />
        </shortcut>
    </shortcuts>
    <data>
        <datum name="datum1">
            <property name="name1" value="value1" />
            <property name="name2" value="value2" />    
        </datum>
        <datum name="datum2">
            <shortcutRef name="shortcut1" />
        </datum>
        <datum name="datum3">
            <shortcutRef name="shortcut1" />
            <property name="name3" value="value3" />    
        </datum>
    </data>
</example>

ご覧のとおり、1 つ以上のプロパティで構成される「ショートカット」を定義できるように構造化されています。データは、プロパティ、1 つ以上のショートカット、または両方の組み合わせを使用して明示的に記述できます (特定の順序はありません)。

これを XmlReader で解析したい (XmlDocument の方が簡単ですが、XML ファイルが大きすぎるため、ここでは機能しません)。これを行う良い方法は、各ショートカットの XML サブツリーを、固有のショートカット名でキー付けされた辞書に格納することだと思いました。次に、それらが参照されると、メインのサブツリーではなく、そのサブツリー XmlReader を読み取ることができます。ただし、サブツリー XmlReader は引き続きメインの XmlReader にリンクする必要があります。これは、出力される XML が期待どおりのものではないためです。これが私のコードです:

using(XmlReader xml = XmlReader.Create("example.xml"))
{
    Dictionary<string, XmlReader> shortcuts = new Dictionary<string, XmlReader>();
    xml.ReadToDescendant("shortcuts");
    xml.ReadToDescendant("shortcut");
    do
    {
        shortcuts.Add(xml.GetAttribute("name"), xml.ReadSubtree());
    } while(xml.ReadToNextSibling("shortcut"));

    xml.ReadToFollowing("data");
    while(xml.ReadToFollowing("datum"))
    {
        Console.WriteLine(xml.GetAttribute("name"));

        XmlReader datum = xml.ReadSubtree();
        while(datum.Read())
        {
            if(datum.Name == "property")
            {
                Console.WriteLine(datum.GetAttribute("name") + ':' + datum.GetAttribute("value"));
            }
            else if(datum.Name == "shortcutRef")
            {
                XmlReader shortcut_ref = shortcuts[datum.GetAttribute("name")];
                while(shortcut_ref.ReadToFollowing("property"))
                {
                    Console.WriteLine(shortcut_ref.GetAttribute("name") + ':' + shortcut_ref.GetAttribute("value"));
                }
            }
        }
    }
}

このように構造化された XML を解析する最良の方法は何ですか?

4

4 に答える 4

1

Mathiesonが示唆するように、LinqToXmlを使用することができます。ルックアップの使用例を次に示します。

XElement root = XElement.Load(file); // or .Parse(string)
var shortcuts = root.Descendants("shortcut").SelectMany(s =>
    s.Elements("property").ToLookup(
        k => k.Parent.Attribute("name").Value,
        v => v.Select(p => new
        {
            Name = p.Attribute("name").Value,
            Value = p.Attribute("value").Value
        })));

これにより、辞書のような構造になりますが、ルックアップにはキーに対して複数の値があります。したがって、ショートカット名ですべてのプロパティを検索できます。

于 2013-02-14T20:04:23.110 に答える
0

何をしたいのか完全に明確ではありませんが、「再生」という言葉を使用しているため、XMLノード(データ/データ)からのすべての値をメモリに保存する必要はないと思います(それらを破棄できますただし、ショートカット プロパティをキャッシュして、それらが参照されたときにそれらを繰り返し処理できるようにする必要があります... ほぼ完了しましたが、XML ノードを格納する代わりに、代わりにオブジェクトをディクショナリに格納するだけです。

public class Property
{
    public string Name { get; set; }
    public string Value { get; set; }
}

public class Shortcut
{
    public List<Property> Properties = new List<Property>();
}

class Program
{
    static void Main(string[] args)
    {
        FileStream fs = new FileStream(@"c:\temp\example.xml", FileMode.Open, FileAccess.Read);
        XmlTextReader reader = new XmlTextReader(fs);

        Dictionary<string, Shortcut> ShortcutDictionary = new Dictionary<string, Shortcut>();

        while (reader.Read())
        {
            if (reader.NodeType == XmlNodeType.Element && reader.LocalName == "shortcuts")
            {
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element && reader.LocalName == "shortcut")
                    {
                        Shortcut shortcut = new Shortcut();
                        ShortcutDictionary.Add(reader.GetAttribute("name"), shortcut);
                        while (reader.Read())
                        {
                            if (reader.NodeType == XmlNodeType.Element && reader.LocalName == "property")
                                shortcut.Properties.Add(new Property() { Name = reader.GetAttribute("name"), Value = reader.GetAttribute("value") });
                            else if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "shortcut")
                                break;
                        }
                    }
                    else if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "shortcuts")
                        break;
                }
            }

            if (reader.NodeType == XmlNodeType.Element && reader.LocalName == "data")
            {
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element && reader.LocalName == "datum")
                    {
                        while (reader.Read())
                        {
                            if (reader.NodeType == XmlNodeType.Element && reader.LocalName == "property")
                            {
                                Console.WriteLine(reader.GetAttribute("name") + ':' + reader.GetAttribute("value"));
                            }
                            else if (reader.NodeType == XmlNodeType.Element && reader.LocalName == "shortcutRef")
                            {
                                foreach (Property property in ShortcutDictionary[reader.GetAttribute("name")].Properties)
                                    Console.WriteLine(property.Name + ':' + property.Value);
                            }
                            else if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "datum")
                                break;
                        }
                    }
                    else if (reader.NodeType == XmlNodeType.EndElement && reader.LocalName == "data")
                        break;
                }
            }
        }

        reader.Close();
        fs.Close();
    }
}

そうでない場合は、シリアル データにランダム アクセス方式でアクセスしようとしています。あなたの最善の策は、データをデータベースに変換/保存することです。SQLite のようなものがそれを行います。

于 2013-02-18T07:08:41.877 に答える
-1

私はxmlシリアライゼーションを使用します。必要な構造を持つ POCO クラス (この場合は、「データ」と「ショートカット」のリストを持つ「サンプル」クラス) を作成し、いくつかのメンバーに注釈を付けて、属性としてレンダリングし、xml シリアル化を呼び出すことができるようにします。これをチェックしてください:

クラスの作成方法: http://www.codeproject.com/Articles/483055/XML-Serialization-and-Deserialization-Part-1

シリアライズとデシリアライズの方法: http://www.codeproject.com/Articles/347758/XML-Serialization-and-Deserialization

于 2013-02-18T14:37:08.747 に答える
-2

一般に、XML ファイルの解析は、次の 2 つの方法で行うことができます。
1. DOM (Document Object Model)
2. SAX (Simple API for XML)

相違点:
DOM パーサーは、入力ドキュメントからメモリ内にツリー構造を作成し、リクエストを待ちます。クライアントから。しかし、SAX パーサーは内部構造を作成しません。代わりに、入力ドキュメントのコンポーネントの発生をイベントとして受け取り、クライアントが入力ドキュメントを読み取るときに何を読み取るかをクライアントに伝えます。
DOM パーサーは、クライアントが実際にどれだけドキュメントを必要としているかに関係なく、常にクライアント アプリケーションにドキュメント全体を提供しますが、SAX パーサーは常にクライアント アプリケーションにドキュメントの断片のみを提供します。
DOM パーサーでは、クライアント アプリケーションでのメソッド呼び出しは明示的である必要があり、一種のチェーンを形成します。しかし、SAX では、いくつかの特定のメソッド (通常は cient によってオーバーライドされる) が、特定のイベントが発生したときに「コールバック」と呼ばれる方法で自動的に (暗黙的に) 呼び出されます。
これらのメソッドは、クライアントが明示的に呼び出す必要はありませんが、明示的に呼び出すこともできます。

DOM
1. ノードのツリー
2. メモリ: より多くのメモリを占有し、小さな XML ドキュメントに適しています
3. 実行時の速度が遅い
4. オブジェクトとして保存される
5. プログラム的に簡単
6. ナビゲーションが
容易SAX
1. イベントのシーケンス
2. 使用しません大きなドキュメントに適した任意のメモリ
3. 実行時の速度が速い
4. オブジェクトを
作成する必要がある 5. オブジェクトを作成するためのコードを記述する必要がある
6. ドキュメントを順次処理するため、後方へのナビゲーションは不可能

実装 .Net フレームワーク:
XmlReader(どういうわけか) DOM モデル、 MSDN refrenceXmlDocumentsに基づいて構築されています。 SAX 用の公式の .Net フレームワーク API は見つかりませんでしたが、Towards a Declarative SAX FrameworkまたはSax for .Netを使用できます。

于 2013-02-19T07:14:21.487 に答える