2012-03-14 19 views
3

F#を使用して特に大きなXML文書を処理しようとしています。ドキュメント全体の読み込みが除外されているので、私は自分の目的に合うようにXmlReaderを使用しようとしています。私の最初のステップは、ノードのシーケンスとしてXML文書を定義することです。F#XML XMLReaderを使用したXML構文解析

// Read XML as a lazy sequence 
let Read (s:string) = 
    let r = XmlReader.Create s 
    let src = seq { 
       while r.Read() 
        do 
         if XmlNodeType.Element = r.NodeType then 
          yield CreateNodeData r 
          while r.MoveToNextAttribute() 
           do 
            yield CreateNodeData r 
           done 
         else 
          yield CreateNodeData r 
        done 
       } 
    LazyList.ofSeq src 

これは、(関数CreateNodeDataによって作成され、単純化のためにここに与えられていない)NODEDATAのシーケンスとしてXML文書を構築します。レイジーリストは、アクティブパターンマッチングを使用するために使用されます。

今、スキーマのパーサは、FParsecのような文法を定義することによって構築されます。例えば、

モナディック構造を追加して、次のコードが与えられた条件に一致するNodeDataを解析するようにモナディックパーサーを作成します。

let item = P (fun inp -> 
    match inp with 
    | NS(LazyList.Nil)   -> [] 
    | NS(LazyList.Cons(a,b)) -> [(a,NS(b))] 
    ) 

let nodeFilter (f: NodeData -> bool) = 
    parser { 
     let! c = item 
     if (f c) then 
      return c 
     } 

また、選択オペレータ(+++)p +++ q代替パーサを表すように付加されます。

私が直面しています問題は、このような

<Node Color="Red" Transparency="90%" Material="Wood"/> 

などの要素でXMLを解析しているここで色、透明度、材料が必要な属性である属性は、しかし、彼らの順序は重要ではありません。さらに、他のオプションの属性もあります。私は

  • オプションの属性
  • これは、次の文字列

    xabc,xacb,xbac,xbca,xcab,xcba

    方法のいずれかに一致すると等価であるハンドリング

    • 配列非依存の属性を表すために、コンビナトリアルパーサを作成するにはどうすればよいです私はそれを簡素化することはできますか?

    答えて

    2

    私の印象は、あなたがホイールを再発明しているということです。

    XmlReaderは完全で効率的なXMLパーサーです。 XmlReaderを使用して属性を解析するのは簡単で、順序に依存しません。シーケンスを構築する際に、必要な属性とオプションの属性を取得するには、XmlReaderを使用できます。属性を読み取るためにとr. MoveToNextAttribute()をチェックしてください。hereMSDN

    言い換えれば、タスク用のパーサーコンビネータを書くことは過度のことです。そして、私はLazyListを使用するとあなたに利点があるとは思わない。おそらくシーケンスを処理するために高次関数を使用します。 seqで始まるのは良い選択です。

    type XmlReader with 
        /// Returns a lazy sequence of XElements matching a given name. 
        member reader.StreamElements(name, ?namespaceURI) = 
         let readOp = 
          match namespaceURI with 
          | None -> fun() -> reader.ReadToFollowing(name) 
          | Some ns -> fun() -> reader.ReadToFollowing(name, ns) 
         seq { 
          while readOp() do 
           match XElement.ReadFrom reader with 
           | :? XElement as el -> yield el 
           | _ ->() 
         } 
    

    あなたはその後、それぞれの属性を照会することができます:あなたはLINQからXMLへのXElementが好きではなくメモリにドキュメント全体をロードしたくない場合は、XmlReaderから個々のXElementインスタンスをストリーミングすることができ

    +0

    解析は、XmlReaderをによって解析されたノードデータを使用しています。主な考え方は、XmlReaderの上にXMLスキーマをオーバーレイし、アプリケーションがHasAttributeなどの関数を呼び出さずに直接データを作成するためのフレームワークを提供することです。 –

    4

    要素、およびソースの順序は関係ありませんが、メモリ全体にロードするのではなく、ドキュメントをストリーミングしています。

    +0

    ありがとう!私はこの解決策が好きです –

    3

    次のことをチェックアウト...多分あなたは見つけることが有用 http://fssnip.net/bd