I’m not quite sure what you mean but here are
basically two ways to affect only elements inside another
element of a certain kind (with a certain tag):
A. If you want to do something with all Image
elements inside any Figure element you can use a local
filter which you apply only to the Figure element. This is
done by calling the `:walk(inner_filter)` method on the
parent/ancestor element.
Some things to keep in mind:
a) The `inner_filter` is a table where
the keys are element tag names and each value are filter
functions to apply to descendants with that tag.
b) The `:walk` method does _not_ change
the element it is called on. Rather it returns a “copy”
with any modifications applied. Thus you have to assign the
return value of `?walk` to a variable, or return the return
value of `:walk` from the outer filter function in turn.
This again can take two forms:
1. If the action of the inner filter
function does not access the parent/ancestor element in any
way it is probably more efficient (and less cluttered) to
define the inner filter only once outside the outer filter
function:
```lua
-- Define static "inner" filter once
local fig_img_filter = {
Image = function(img)
-- Do something with Image
img.attributes.style = 'border:
0.2rem solid black'
return img
end
}
-- Main filter function
function Figure(fig)
-- Apply "inner" filter to images
inside the Figure
return fig:walk(fig_img_filter)
end
```
2. If on the other hand the inner filter
function needs to access the parent/ancestor element you
need to define the inner filter inside the outer filter
function where the parent is in scope:
```lua
function Div(div)
-- Test condition on div
if div.classes:includes('foo') then
-- Apply dynamic filter to nested
links
return div:walk({
Link = function(lnk)
-- Test condition on link
if lnk.classes:includes('bar')
then
-- Copy something from div
lnk.attributes.baz =
div.attributes.zip
else
-- Copy something else from
div
lnk.attributes.baz =
div.attributes.zap
end
return lnk
end
}).content
-- Div is not needed anymore so
replace it with its content
end
end
```
This also illustrates the common
situation where a Div or Span is only used to tell the
filter what to do to elements inside it. In this case the
Div is no longer needed when you have applied the changes to
the elements inside it, so rather than returning the Div you
return only what is inside it.
B. In case you want to do something only with
specific descendants of an element you have to walk/check
the children at each level manually.
Some things to remember:
a) You need to check that any child exist
separately before accessing its properties, because trying
to access properties on a non-existing value is a fatal
error.
b) Don’t forget to reassign any elements
which you have changed to the right place in the structure
or the change may not take effect. It’s not all that clear
when it is needed so it’s safer to do it always.
Here is a more explicit version (with more
comments and some extras :-) of my filter for conditionally
stripping the Figure around an Image:
```lua
function Figure(fig)
-- First check that we have exactly one
child...
if 1 == #fig.content then
local child = fig.content[1]
-- ...then check that the child is a
Plain...
if 'Plain' == child.tag then
-- ...then check that there is
exactly one grandchild...
if 1 == #child.content then
local grandchild =
child.content[1]
-- ...and that the grandchild is
an Image.
if 'Image' == grandchild.tag then
-- Bingo!
-- Now do we want it to be a
figure?
if
grandchild.classes:includes('fig') then
grandchild.attributes.style =
style_for_img_in_fig
-- Put grandchild back
child.content[1] = grandchild
-- Put child back
fig.content[1] = child
fig.attributes.style =
style_for_figs
-- Done with figure
return fig
end
-- else if a standalone image
grandchild.attributes.style =
style_for_img
-- Don't want the fig so return
the image!
return granchild
end
end
end
end
-- If not all the conditions hold
return nil
end
```
(Note: the `style_for_*` variables aren’t
actually defined in this code; they are just placeholders
for some strings!)
`pandoc.utils.stringify` concatenates and
returns the Str element values in its argument, which must be
an element object. The attributes of an element don't meet any
of those two descriptions, but they are an object with custom
stringification (in the Lua sense) so you can just say
`print(element.attributes)` to inspect them.
No.