Хаскелл |Как получить значение из глубоко вложенной структуры данных? - PullRequest
0 голосов
/ 18 декабря 2018

Я новичок в Haskell, и я пытаюсь узнать больше о языке, выполнив некоторый базовый синтаксический анализ.

У меня есть некоторый код, который анализирует файл XML и выдает это

[ Element
    { elName = QName
        { qName = "title"
        , qURI = Nothing
        , qPrefix = Nothing
        }
    , elAttribs = []
    , elContent =
        [ Text
            ( CData
                { cdVerbatim = CDataText
                , cdData = "This string is what I want to obtain" -- string to view.
                , cdLine = Just 27
                }
            )
        ]
    , elLine = Just 27
    }
]

Где Element - это просто тип данных *1008* библиотеки XML

Что я хочу сделать, это получить строку "This string is what I want to obtain"

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

Я провел общее исследование и обнаружил библиотеку Lens , и, хотя было несколько учебных пособий, я все еще пытаюсь разобрать вложенные данные.структура.

Это файл XML, который я пытаюсь проанализировать, выглядит

<GoodreadsResponse>
    <Request>
        <authentication>true</authentication>
        <key>HOKCk4yYS8UjyducqmgRw</key>
        <method>search_search</method>
    </Request>
    <search>
        <query>fantasy</query>
        <results-start>1</results-start>
        <results-end>20</results-end>
        <total-results>35221</total-results>
        <source>Goodreads</source>
        <query-time-seconds>0.21</query-time-seconds>
        <results>
            <work>
                <id type="integer">2384</id>
                <books_count type="integer">51</books_count>
                <ratings_count type="integer">78825</ratings_count>
                <text_reviews_count type="integer">3357</text_reviews_count>
                <original_publication_year type="integer">2002</original_publication_year>
                <original_publication_month type="integer">2</original_publication_month>
                <original_publication_day type="integer">18</original_publication_day>
                <average_rating>4.17</average_rating>
                <best_book type="Book">
                    <id type="integer">84136</id>
                    <title>Fantasy Lover (Hunter Legends Series #1)</title>
                    <author>
                        <id type="integer">4430</id>
                        <name>Sherrilyn Kenyon</name>
                    </author>
                    <image_url>https://images.gr-assets.com/books/1348332807m/84136.jpg</image_url>
                    <small_image_url>https://images.gr-assets.com/books/1348332807s/84136.jpg</small_image_url>
                </best_book>
            </work>
            <work>
                <id type="integer">6734901</id>
                <books_count type="integer">42</books_count>
                <ratings_count type="integer">18358</ratings_count>
                <text_reviews_count type="integer">985</text_reviews_count>
                <original_publication_year type="integer">2010</original_publication_year>
                <original_publication_month type="integer" nil="true"/>
                <original_publication_day type="integer" nil="true"/>
                <average_rating>4.26</average_rating>
                <best_book type="Book">
                    <id type="integer">6542645</id>
                    <title>Fantasy in Death (In Death, #30)</title>
                    <author>
                        <id type="integer">17065</id>
                        <name>J.D. Robb</name>
                    </author>
                    <image_url>https://s.gr-assets.com/assets/nophoto/book/111x148-bcc042a9c91a29c1d680899eff700a03.png</image_url>
                    <small_image_url>https://s.gr-assets.com/assets/nophoto/book/50x75-a91bf249278a81aabab721ef782c4a74.png</small_image_url>
                </best_book>
            </work>
       ...
       ...

Ответы [ 2 ]

0 голосов
/ 18 декабря 2018

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

get :: [Element] -> [String]
get es = [cdData c | e <- es, Text c <- elContent e ]

Шаблон Text c автоматически отфильтрует любые значения Elem e или CRef s в elContent e.

Как только вы узнаете, что для списков =<< означает concatMap, вы можете сохранить несколько символов с помощью

get :: [Element] -> [String]
get es = [cdData c | Text c <- elContent =<< es]

Дополнительно, если вы хотите, чтобы cdData был только тогда, когда cdVerbatim было CDataText, вы можете добавить это условие.

get :: [Element] -> [String]
get es = [cdData c | Text c <- elContent =<< es, cdVerbatim c == CDataText ]
0 голосов
/ 18 декабря 2018

Поскольку xml не определяет саму оптику, вам понадобится другой пакет, который это делает.@ Li-yaoXia нашел один: lens-xml.

 #!/usr/bin/env cabal
 {- cabal:
 build-depends: base
              , xml
              , lens
              , lens-xml
 -}
 {-# LANGUAGE OverloadedStrings #-}

 import Control.Lens
 import Text.XML.Light.Types
 import Text.XML.Light.Lens

 x = [ Element
         { elName = QName
             { qName = "title"
             , qURI = Nothing
             , qPrefix = Nothing
             }
         , elAttribs = []
         , elContent =
             [ Text
                 ( CData
                     { cdVerbatim = CDataText
                     , cdData = "This string is what I want to obtain" -- string to view.
                     , cdLine = Just 27
                     }
                 )
             ]
         , elLine = Just 27
         }
     ]

 main :: IO ()
 main = print (x ^? ix 0 . elContentL . ix 0 . _Text . cdDataL)

Вы можете запустить его с последней версией cabal:

$ cabal new-run Main.hs
<<lots of build output snipped>>
Just "This string is what I want to obtain"

Отказ от ответственности : я не уверен, что согласился бы с идеей использования lens для этой задачи.Лично я предпочел бы сначала преобразовать XML в тип данных (с сообщениями об ошибках, когда XML не соответствует ожидаемой схеме), а затем работать над этим типом данных.Тем не менее, вы запросили решение на основе lens ...

...