Search code examples
haskellhaskell-lens

Extract nth-child with xml-lens


I'm trying to get the first <bar>'s text node with xml-lens from an XML like this:

<foo>
  <bar>
    I want ONLY this!
  </bar>
  <bar>
    I DON'T want this!
  </bar>
</foo>

In other words, I want to write a lens expression equivalent with XPath /foo/bar[1]/text()

First, I wrote a haskell script like below:

{-# LANGUAGE OverloadedStrings #-}

import           Control.Lens
import           Text.XML.Lens
import           Text.HTML.DOM
import qualified Data.Text.Lazy as T
import qualified Data.Text.Lazy.IO as TIO

main :: IO ()
main = do
  input <- TIO.getContents
  parseLT input & toListOf (root . el "foo" ./ indexing (el "bar") . index 0 . text) & map T.fromStrict & T.unlines & TIO.putStr

But Actually got both first and second <bar>'s texts:

> stack runghc sample.hs  < input.xml

    I want ONLY this!


    I DON'T want this!

Isn't this possible with current xml-lens implementation? Should I submit an issue to xml-lens or some other project?


Solution

  • This is correct behavior.

    indexing assigns indices to targets of a traversal; el has at most one target so only 0 will be given.

    You may want to use el "foo" . indexing (plate . el "bar") . index 0 or el "foo" . elementOf (plate . el "bar") 0 instead. These handle multiple occurrences of "bar".