Как вы сохраняете «состояние» при анализе SAX с помощью Haskell (HaXml) - PullRequest
2 голосов
/ 16 ноября 2011

Я совершенно новичок в Haskell, и для моей первой настоящей проблемы с Haskell я пытаюсь проанализировать огромный XML-файл с помощью синтаксического анализа HaXml SAX.

Большая проблема, с которой я сталкиваюськак выяснить, что является тегом включающего элемента любого конкретного SaxElement charData.Если бы я делал это на императивном языке, у меня был бы просто объект Array с сохранением состояния, который поддерживает стек тегов элементов при возникновении событий SAX.Я бы помещал имя элемента в стек, когда встречается «SAX.SaxElementOpen», и выталкивал одно, когда встречался «SAX.SaxElementClose».Тогда, если бы я получил событие / элемент SAX.SaxCharData, я мог бы просто посмотреть на вершину стека, чтобы увидеть, в какой тег он был заключен.

Теперь, когда я пытаюсь решить эту проблему в HaskellЯ понятия не имею, как обойти отсутствие глобальных переменных состояния.У меня есть только смутное представление о том, что делают Монады, поэтому, если они являются решением, я мог бы использовать совет или два.

Вот, надеюсь, достаточно кода, чтобы показать, как далеко я продвинулся:

module Main where

import qualified Text.XML.HaXml.SAX as SAX
import Text.XML.HaXml
import Data.Maybe
import Text.XML.HaXml.Namespaces

main = let inputFilename = "/path/to/file.xml" in
    do content <- readFile inputFilename
       let (elements, error) = SAX.saxParse inputFilename content
       mapM_ putStrLn (summarizeElements elements)

summarizeElements :: [SAX.SaxElement] -> [String]
summarizeElements elements = filter (\s -> length s > 0) $ map summarizeElement elements

summarizeElement :: SAX.SaxElement -> String
summarizeElement element = case element of
    (SAX.SaxElementOpen name attrs)  -> myProcessElem name attrs
    (SAX.SaxCharData charData)       -> myProcessCharData charData 
    (SAX.SaxElementTag name attrs)  -> myProcessElem name attrs
    _ -> ""

1 Ответ

1 голос
/ 16 ноября 2011

Проблема здесь в том, что map не несет состояние, как вы хотите. Простой подход - написать то, что вы хотите, как рекурсивную функцию, которая передает состояние через рекурсивные вызовы. Вам нужно будет решить, какой тип значения вы сохраните в стеке состояний, но тогда это просто вопрос ...

go :: MyStack -> [SAX.SaxElement] -> [String]
go _ [] = []
go s (e:es) = myProcessElem e : go s' es
  where s' = pushPop s
...