我有一个扫描HTML字符串的方法,并为prawnpdf格式化它:
def format_for_prawn(pdf, string, colour)
body = Nokogiri::HTML::DocumentFragment.parse(string)
result = body.xpath('./*|./text()')
result.each do |breaker|
if breaker.name == "h3"
pdf.fill_color colour
pdf.text breaker.text.to_s, :size => 16
pdf.move_down 5
else
pdf.fill_color '#444444'
pdf.text breaker.text.to_s, :size => 10, :leading => 1
pdf.move_down 10
end
end
end
它适用于<h3>
。如果找到一些中段<b>
(或类似)标签,它会启动一个新段落,因为这是Nokogiri打破字符串的地方 - 这是正确的行为。
如何将粗体字符串添加到上一个pdf.text
函数,而不是调用新的pdf.text
,从而产生新的段落?
我想过制作一个阵列,但是它会与<h3>
s无关。
任何帮助都将不胜感激。
答案 0 :(得分:1)
我的第一个想法是做一场负面比赛:
body.xpath( './node()[not(self::b)]' )
可悲的是,这会排除<b>
而不是忽略它:
> body = Nokogiri::HTML::DocumentFragment.parse %(<h3><b>foo</b></h3><h3>bar</h3>fooz<b>baz</b>whatever); true
> body.xpath( './node()[not(self::b)]' ).to_a
[
[0] <h3>
<b>foo</b>
</h3>,
[1] <h3>bar</h3>,
[2] fooz,
[3] whatever
]
所以,你将别无选择,只能使用缓冲区,这里:我们可以先遍历节点,填充一个缓冲区,看看我们是否应该有一个新行,然后迭代这个缓冲区以添加你的行pdf:
buffer = []
body.xpath( './node()' ).each do |node|
if %w[text b].include? node.name
# add to previous line or create one
buffer << [] unless buffer.count
buffer.last << { node: node }
else
# set content and create a new line
buffer << [ { node: node, title: node.name == 'h3' } ]
buffer << []
end
end
# Now, each first level item in buffer is a line,
# containing elements we just have to concatenate text of
# to pass to `pdf#text`
buffer.each do |line|
text = line.map do |part|
node = part[ :node ]
inner = node.text.to_s
# restore <b> tag if you want bold style in pdf
node.name == 'b' ? "<b>#{inner}</b>" : inner
end.join
if line.first
if line.first[ :title ]
pdf.fill_color colour
pdf.text text, :size => 16
pdf.move_down 5
else
pdf.fill_color '#444444'
# inline_format ensure basic html formating is used, <b> in our case
# See http://prawn.majesticseacreature.com/docs/0.11.1/Prawn/Text.html#method-i-text
pdf.text text, size: 10, leading: 1, inline_format: true
pdf.move_down 10
end
end
end
当然,所有这些都考虑到你不控制原始的HTML。否则,您应该将文本节点放在<p>
或其他内容中,并且不再存在问题。