Разбор F # XML с использованием XMLReader - PullRequest
3 голосов
/ 14 марта 2012

Я пытаюсь обработать особенно большой XML-документ, используя F #.Поскольку загрузка всего документа исключена, я пытаюсь использовать 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

Это создает XML-документ как последовательность NodeData (которая создается функцией CreateNodeData и не приводится здесь для простоты).Ленивый список используется для использования активного сопоставления с образцом.

Теперь синтаксический анализатор для схемы создается путем определения грамматики, такой как FParsec.Например,

type NodeSeq = NS of LazyList<NodeData>

(* 
Define a generic parser that takes an XML Reader and returns a singleton
list containing parsed element and unparsed parser. Failure is denoted by 
an empty list 
*)

type 'a Parser = P of ( NodeSeq -> list<'a * NodeSeq > )

И добавление монадических конструкций для создания монадического синтаксического анализатора таким образом, чтобы следующий код анализировал 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 представляет альтернативные парсеры.

Проблема, с которой я сталкиваюсь, заключается в анализе XML с таким элементом, как

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

Здесь атрибуты Color, Transparency и Material являются обязательными атрибутами, однакоИх последовательность не имеет значения.Кроме того, могут быть другие необязательные атрибуты.Как создать комбинаторный анализатор для представления

  • независимой от последовательности обработки атрибутов
  • необязательных атрибутов

Это эквивалентно сопоставлению с любой из следующих строк

xabc,xacb,xbac,xbca,xcab,xcba

Как мне это упростить?

Ответы [ 3 ]

4 голосов
/ 15 марта 2012

Если вам нравится XElement из LINQ в XML, но вы не хотите загружать весь документ в память, вы можете передавать отдельные экземпляры XElement из XmlReader:

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
                | _ -> ()
        }

Затем вы можете запросить атрибутыкаждый элемент и исходный порядок атрибутов не будут иметь значения, но вы все равно используете потоковую передачу документа, а не загружаете все это в память.

3 голосов
/ 21 марта 2012

Проверьте следующее ... может быть, вы найдете это полезным http://fssnip.net/bd

2 голосов
/ 14 марта 2012

У меня сложилось впечатление, что вы заново изобретаете колесо.

XmlReader - это полный и эффективный анализатор XML.Синтаксический анализ XmlReader прост и не зависит от их порядка.Вы можете использовать XmlReader для получения обязательных и дополнительных атрибутов при построении последовательности.Проверьте r.HasAttribute и r. MoveToNextAttribute() для чтения атрибутов здесь MSDN .

Тем не менее, написание комбинатора синтаксического анализа для задачиизлишество.И я сомневаюсь, что использование LazyList даст вам какое-либо преимущество.Скорее всего, вы будете использовать функции высокого порядка для обработки последовательности;начиная с seq - хороший выбор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...