LINUX.ORG.RU

Распарсить большой XML на хаскеле

 


2

3

Пример большого XML-файла (~100 MiB):

wget -O - "http://mirror.yandex.ru/fedora/linux/releases/21/Everything/x86_64/os/repodata/e2a28baab2ea4632fad93f9f28144cda3458190888fdf7f2acc9bc289f397e96-primary.xml.gz" | gunzip >test-primary.xml
Код с использованием xml-conduit (практически копипаста из документации):
#!/usr/bin/runhaskell

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PackageImports #-}

import Prelude hiding (readFile, writeFile)
import "xml-conduit" Text.XML
import "xml-conduit" Text.XML.Cursor

main :: IO ()
main = do
    doc <- readFile def "test-primary.xml"
    let cursor = fromDocument doc
    mapM_ print $ cursor $/ laxElement "package" &/ laxElement "name" &/ content
Результат:
$ /usr/bin/time ./test >/dev/null
22.12user 1.24system 0:23.38elapsed 99%CPU (0avgtext+0avgdata 3906128maxresident)k
0inputs+0outputs (0major+975026minor)pagefaults 0swaps
Съело четыре гига на ровном месте. Как это починить?

Deleted

Ответ на: комментарий от qnikst

да, я забыл что функциональщики придумали реализовывать циклы через рекурсию и таскать ВСЁ состояние через аргументы. так что насчет «никак» я был неправ.

удачи в удалении гландов через жопу.

crowbar
()
Ответ на: комментарий от qnikst

public class Test {
    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        Document document = documentBuilder.parse(new File("/Users/vbezhenar/tmp/test-primary.xml"));

        long start = System.currentTimeMillis();
        processElemMetadata(document.getDocumentElement());
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

    private static void processElemMetadata(Element elemMetadata) {
        NodeList nodesMetadataChildren = elemMetadata.getChildNodes();
        for (int metadataChildIndex = 0; metadataChildIndex < nodesMetadataChildren.getLength(); metadataChildIndex++) {
            Node nodeMetadataChild = nodesMetadataChildren.item(metadataChildIndex);
            if (nodeMetadataChild.getNodeType() != Node.ELEMENT_NODE) {
                continue;
            }
            Element elemMetadataChild = (Element) nodeMetadataChild;
            if (!elemMetadataChild.getTagName().equals("package")) {
                continue;
            }
            processElemPackage(elemMetadataChild);
        }
    }

    private static void processElemPackage(Element elemPackage) {
        NodeList nodesPackageChildren = elemPackage.getChildNodes();
        for (int packageChildIndex = 0; packageChildIndex < nodesPackageChildren.getLength(); packageChildIndex++) {
            Node nodePackageChild = nodesPackageChildren.item(packageChildIndex);
            if (nodePackageChild.getNodeType() != Node.ELEMENT_NODE) {
                continue;
            }
            Element elemPackageChild = (Element) nodePackageChild;
            if (!elemPackageChild.getTagName().equals("name")) {
                continue;
            }
            processElemName(elemPackageChild);
        }
    }

    private static void processElemName(Element elemName) {
        System.out.println(elemName.getTextContent());
    }
}

Это ручками ходить. Не-ручками это использовать декларативное XPath-выражение.

Legioner ★★★★★
()
Ответ на: комментарий от crowbar

спасибо, ваше мнение безусловно заслуживает внимания и дальшейшего обсуждения.

qnikst ★★★★★
()
Ответ на: комментарий от qnikst
data S = S1 | S2 | S3

main = do
    dat_ <- LBS.readFile "test-primary.xml"
    void $ foldlM go S1 (parseTags dat_)
    where
        go S1 (TagOpen "package" _) = return S2
        go S2 (TagOpen "name"    _) = return S3
        go S2 (TagClose "package")  = return S1
        go S3 (TagText  t)          = LBS.putStrLn t >> return S2
        go s  _                     = return s

вот так поаккуратнее, но медленнее, чем на яве, т.к. там многопоточный парсер, зато Maximum resident set size (kbytes): 7280

qnikst ★★★★★
()
Ответ на: комментарий от SystemD-hater

Все вопросы к анонимусу, я лишь резюмировал, возможно, неверно.

Virtuos86 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.