简体   繁体   中英

Pandoc Lua : how to walk inside a div?

I need the two BulletList to be treated differently.

The one inside the Div is correctly parsed when I simply return the element in the normal BulletList.

But how to make the walk inside the div work when I change the normal Bulletlist and return RawInline?

# normal chapter
* a normal list
* with items
* or more
* to finish

::: Special

# special chapter
* at the start
* something else
* the end

:::

The expected result would be like this. The items of each list are differently treated.

<h1 class="normalHeader" id="normal-chapter">normal chapter</h1>
<ul>
<li class="normal-item">a normal list</li>
<li class="normal-item">with items</li>
<li class="normal-item">or more</li>
<li class="normal-item">to finish</li>
</ul>
<section id="special-chapter" class="Special" class="specialHeader">
<h1 class="specialHeader">special chapter</h1>
<ul >
<li class="special-item">at the start</li>
<li class="special-item">something else</li>
<li class="special-item">the end</li>
</ul>

</section>

Lua filter:


Div = function (el)
    if el.classes[1] == 'Special' then
      return pandoc.walk_block(el, {
        Header = function(el)
            el.attributes['class']='specialHeader'
            return el
        end,
        BulletList = function(el)
            print("specialltest")
              local mylist ='<ul >\n'
              for i, item in ipairs(el.content) do
                local first = item[1]
                if first  then
                  mylist =  mylist .. '<li class="special-item">' .. pandoc.utils.stringify(first) ..  '</li>\n'
                end
              end
           mylist =  mylist .. '</ul>\n'
           return pandoc.RawInline('html', mylist)
        end,
      })
    end
    return el
end

Header = function (el)
    el.attributes['class']='normalHeader'
    return el
end


BulletList = function (el)
            print("normalltest")
              local mylist ='<ul >\n'
              for i, item in ipairs(el.content) do
                local first = item[1]
                if first  then
                  mylist =  mylist .. '<li class="normal-item">' .. pandoc.utils.stringify(first) ..  '</li>\n'
                end
              end
           mylist =  mylist .. '</ul>\n'
           return pandoc.RawInline('html', mylist)
           -- works if I return el without treatment
end

Below is a possible way to solve this. It defines two filters, one for the normal environments, one for the special environments inside some divs. The kind of filter to be used is selected inside the div. The filters use a non-standard traversal order ( traverse = 'topdown' ). We apply the normal filter to the whole document to make sure that it will be applied to elements not wrapped in a div.

Note that some filter functions now return false as a second value: this signals to pandoc that the element's subtree should not be filtered any further.

local normal_filter, special_filter
special_filter = {
  traverse = 'topdown',
  Header = function(el)
    el.classes = {'specialHeader'}
    return el
  end,
  BulletList = function (el)
    local mylist ='<ul >\n'
    for i, item in ipairs(el.content) do
      local first = item[1]
      if first  then
        mylist =  mylist .. '<li class="special-item">' .. pandoc.utils.stringify(first) ..  '</li>\n'
      end
    end
    mylist =  mylist .. '</ul>\n'
    return pandoc.RawInline('html', mylist)
  end
}

normal_filter = {
  traverse = 'topdown',
  Header = function (el)
    el.classes = {'normalHeader'}
    return el
  end,
  BulletList = function (el)
    local mylist ='<ul >\n'
    for i, item in ipairs(el.content) do
      local first = item[1]
      if first  then
        mylist =  mylist .. '<li class="normal-item">' .. pandoc.utils.stringify(first) ..  '</li>\n'
      end
    end
    mylist =  mylist .. '</ul>\n'
    return pandoc.RawInline('html', mylist)
  end,

  Div = function (div)
    local filter

    if div.classes[1] == 'Special' then
      filter = special_filter
    else
      filter = normal_filter
    end
    return div:walk(filter), false
  end
}

Pandoc = function (doc)
  return doc:walk(normal_filter)
end

The reason for the above filter not working is that pandoc traverses the document tree bottom-up, ie, it processes the deeply nested elements first. So it processes the nested bullet list before it processes the div. After that, the div no longer contains a bullet list but raw content; the latter is not processed by the filter.

That's also why the code did work for the heading: the Header is modified instead of replaced, so the Div filter can modify it further.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM