解析 'ul' 和 'ol' 标签
Parse 'ul' and 'ol' tags
我必须处理 ul
、ol
和 li
标签的深度嵌套。我需要提供与我们在浏览器中提供的视图相同的视图。我想在pdf文件中实现以下示例:
text = "
<body>
<ol>
<li>One</li>
<li>Two
<ol>
<li>Inner One</li>
<li>inner Two
<ul>
<li>hey
<ol>
<li>hiiiiiiiii</li>
<li>why</li>
<li>hiiiiiiiii</li>
</ol>
</li>
<li>aniket </li>
</li>
</ul>
<li>sup </li>
<li>there </li>
</ol>
<li>hey </li>
<li>Three</li>
</li>
</ol>
<ol>
<li>Introduction</li>
<ol>
<li>Introduction</li>
</ol>
<li>Description</li>
<li>Observation</li>
<li>Results</li>
<li>Summary</li>
</ol>
<ul>
<li>Introduction</li>
<li>Description
<ul>
<li>Observation
<ul>
<li>Results
<ul>
<li>Summary</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Overview</li>
</ul>
</body>"
我必须用大虾来完成我的任务。但是大虾不支持HTML标签。所以,我想出了一个使用 nokogiri
: 的解决方案。我正在解析并稍后删除带有 gsub 的标签。我为上述内容的一部分编写了以下解决方案,但问题是 ul 和 ol 可能会有所不同。
RULES = {
ol: {
1 => ->(index) { "#{index + 1}. " },
2 => ->(index) { "#{}" },
3 => ->(index) { "#{}" },
4 => ->(index) { "#{}" }
},
ul: {
1 => ->(_) { "\u2022 " },
2 => ->(_) { "" },
3 => ->(_) { "" },
4 => ->(_) { "" },
}
}
def ol_rule(group, deepness: 1)
group.search('> li').each_with_index do |item, i|
prefix = RULES[:ol][deepness].call(i)
item.prepend_child(prefix)
descend(item, deepness + 1)
end
end
def ul_rule(group, deepness: 1)
group.search('> li').each_with_index do |item, i|
prefix = RULES[:ul][deepness].call(i)
item.prepend_child(prefix)
descend(item, deepness + 1)
end
end
def descend(item, deepness)
item.search('> ol').each do |ol|
ol_rule(ol, deepness: deepness)
end
item.search('> ul').each do |ul|
ul_rule(ul, deepness: deepness)
end
end
doc = Nokogiri::HTML.fragment(text)
doc.search('ol').each do |group|
ol_rule(group, deepness: 1)
end
doc.search('ul').each do |group|
ul_rule(group, deepness: 1)
end
puts doc.inner_text
1. One
2. Two
1. Inner One
2. inner Two
• hey
1. hiiiiiiiii
2. why
3. hiiiiiiiii
• aniket
3. sup
4. there
3. hey
4. Three
1. Introduction
1. Introduction
2. Description
3. Observation
4. Results
5. Summary
• Introduction
• Description
• Observation
• Results
• Summary
• Overview
问题
1) 我想要实现的是在使用 ul 和 ol 标签时如何处理 space
2) 当 li 进入 ul 或 li 进入 ol
时如何处理深层嵌套
无论何时在 ol
、li
或 ul
元素中,都必须递归检查 ol
、li
和 ul
.如果有none个,return(作为子结构被发现的),如果有,在新节点上调用相同的函数并将其return值添加到当前结构。
无论节点在哪里,您都可以根据其类型对每个节点执行不同的操作,然后该函数会自动重新打包所有内容。
我想出了一个解决方案,可以处理多个标识,每个级别都有可配置的编号规则:
require 'nokogiri'
ROMANS = %w[i ii iii iv v vi vii viii ix]
RULES = {
ol: {
1 => ->(index) { "#{index + 1}. " },
2 => ->(index) { "#{('a'..'z').to_a[index]}. " },
3 => ->(index) { "#{ROMANS.to_a[index]}. " },
4 => ->(index) { "#{ROMANS.to_a[index].upcase}. " }
},
ul: {
1 => ->(_) { "\u2022 " },
2 => ->(_) { "\u25E6 " },
3 => ->(_) { "* " },
4 => ->(_) { "- " },
}
}
def ol_rule(group, deepness: 1)
group.search('> li').each_with_index do |item, i|
prefix = RULES[:ol][deepness].call(i)
item.prepend_child(prefix)
descend(item, deepness + 1)
end
end
def ul_rule(group, deepness: 1)
group.search('> li').each_with_index do |item, i|
prefix = RULES[:ul][deepness].call(i)
item.prepend_child(prefix)
descend(item, deepness + 1)
end
end
def descend(item, deepness)
item.search('> ol').each do |ol|
ol_rule(ol, deepness: deepness)
end
item.search('> ul').each do |ul|
ul_rule(ul, deepness: deepness)
end
end
doc = Nokogiri::HTML.fragment(text)
doc.search('ol:root').each do |group|
binding.pry
ol_rule(group, deepness: 1)
end
doc.search('ul:root').each do |group|
ul_rule(group, deepness: 1)
end
然后您可以删除标签或使用 doc.inner_text,具体取决于您的环境。
但有两个注意事项:
- 必须仔细选择您的条目选择器。我在没有根元素的情况下逐字使用了您的代码段,因此我不得不使用 ul:root/ol:root。也许 "body > ol" 也适用于您的情况。也许选择每个 ol/ul 但不是遍历每个并且只找到那些没有列表父级的。
- 逐字使用您的示例,Nokogiri 不能很好地处理第一组 ol 的最后 2 个列表项("hey","Three")
当用 nokogiri 解析时,元素已经 "left" 它们的 ol 树并被放置在根树中。
当前输出:
1. One
2. Two
a. Inner One
b. inner Two
◦ hey
◦ hey
3. hey
4. hey
hey
Three
1. Introduction
a. Introduction
2. Description
3. Observation
4. Results
5. Summary
• Introduction
• Description
◦ Observation
* Results
- Summary
• Overview
首先为了处理 space,我在 lambda 调用中使用了 hack。
此外,我正在使用 nokogiri 提供的 add_previous_sibling 函数在开始时附加一些内容。最后,当我们处理 ul 和 ol 标签时,Prawn 不处理 space 因此我使用了这个 gsub gsub(/^([^\S\r\n]+)/m) { |米| “\xC2\xA0”*m.size}。您可以阅读更多内容 link
注意:Nokogiri 不处理无效 HTML 所以总是提供有效 HTML
RULES = {
ol: {
1 => ->(index) { "#{index + 1}. " },
2 => ->(index) { "#{}" },
3 => ->(index) { "#{}" },
4 => ->(index) { "#{}" }
},
ul: {
1 => ->(_) { "\u2022 " },
2 => ->(_) { "" },
3 => ->(_) { "" },
4 => ->(_) { "" },
},
space: {
1 => ->(index) { " " },
2 => ->(index) { " " },
3 => ->(index) { " " },
4 => ->(index) { " " },
}
}
def ol_rule(group, deepness: 1)
group.search('> li').each_with_index do |item, i|
prefix = RULES[:ol][deepness].call(i)
space = RULES[:space][deepness].call(i)
item.add_previous_sibling(space)
item.prepend_child(prefix)
descend(item, deepness + 1)
end
end
def ul_rule(group, deepness: 1)
group.search('> li').each_with_index do |item, i|
space = RULES[:space][deepness].call(i)
prefix = RULES[:ul][deepness].call(i)
item.add_previous_sibling(space)
item.prepend_child(prefix)
descend(item, deepness + 1)
end
end
def descend(item, deepness)
item.search('> ol').each do |ol|
ol_rule(ol, deepness: deepness)
end
item.search('> ul').each do |ul|
ul_rule(ul, deepness: deepness)
end
end
doc = Nokogiri::HTML.parse(text)
doc.search('ol').each do |group|
ol_rule(group, deepness: 1)
end
doc.search('ul').each do |group|
ul_rule(group, deepness: 1)
end
Prawn::Document.generate("hello.pdf") do
#puts doc.inner_text
text doc.at('body').children.to_html.gsub(/^([^\S\r\n]+)/m) { |m| "\xC2\xA0" * m.size }.gsub("<ul>","").gsub("<\/ul>","").gsub("<ol>","").gsub("<\/ol>","").gsub("<li>", "").gsub("</li>","").gsub("\n","").gsub(/[\n]+/, "\n")
end
我必须处理 ul
、ol
和 li
标签的深度嵌套。我需要提供与我们在浏览器中提供的视图相同的视图。我想在pdf文件中实现以下示例:
text = "
<body>
<ol>
<li>One</li>
<li>Two
<ol>
<li>Inner One</li>
<li>inner Two
<ul>
<li>hey
<ol>
<li>hiiiiiiiii</li>
<li>why</li>
<li>hiiiiiiiii</li>
</ol>
</li>
<li>aniket </li>
</li>
</ul>
<li>sup </li>
<li>there </li>
</ol>
<li>hey </li>
<li>Three</li>
</li>
</ol>
<ol>
<li>Introduction</li>
<ol>
<li>Introduction</li>
</ol>
<li>Description</li>
<li>Observation</li>
<li>Results</li>
<li>Summary</li>
</ol>
<ul>
<li>Introduction</li>
<li>Description
<ul>
<li>Observation
<ul>
<li>Results
<ul>
<li>Summary</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>Overview</li>
</ul>
</body>"
我必须用大虾来完成我的任务。但是大虾不支持HTML标签。所以,我想出了一个使用 nokogiri
: 的解决方案。我正在解析并稍后删除带有 gsub 的标签。我为上述内容的一部分编写了以下解决方案,但问题是 ul 和 ol 可能会有所不同。
RULES = {
ol: {
1 => ->(index) { "#{index + 1}. " },
2 => ->(index) { "#{}" },
3 => ->(index) { "#{}" },
4 => ->(index) { "#{}" }
},
ul: {
1 => ->(_) { "\u2022 " },
2 => ->(_) { "" },
3 => ->(_) { "" },
4 => ->(_) { "" },
}
}
def ol_rule(group, deepness: 1)
group.search('> li').each_with_index do |item, i|
prefix = RULES[:ol][deepness].call(i)
item.prepend_child(prefix)
descend(item, deepness + 1)
end
end
def ul_rule(group, deepness: 1)
group.search('> li').each_with_index do |item, i|
prefix = RULES[:ul][deepness].call(i)
item.prepend_child(prefix)
descend(item, deepness + 1)
end
end
def descend(item, deepness)
item.search('> ol').each do |ol|
ol_rule(ol, deepness: deepness)
end
item.search('> ul').each do |ul|
ul_rule(ul, deepness: deepness)
end
end
doc = Nokogiri::HTML.fragment(text)
doc.search('ol').each do |group|
ol_rule(group, deepness: 1)
end
doc.search('ul').each do |group|
ul_rule(group, deepness: 1)
end
puts doc.inner_text
1. One
2. Two
1. Inner One
2. inner Two
• hey
1. hiiiiiiiii
2. why
3. hiiiiiiiii
• aniket
3. sup
4. there
3. hey
4. Three
1. Introduction
1. Introduction
2. Description
3. Observation
4. Results
5. Summary
• Introduction
• Description
• Observation
• Results
• Summary
• Overview
问题
1) 我想要实现的是在使用 ul 和 ol 标签时如何处理 space
2) 当 li 进入 ul 或 li 进入 ol
无论何时在 ol
、li
或 ul
元素中,都必须递归检查 ol
、li
和 ul
.如果有none个,return(作为子结构被发现的),如果有,在新节点上调用相同的函数并将其return值添加到当前结构。
无论节点在哪里,您都可以根据其类型对每个节点执行不同的操作,然后该函数会自动重新打包所有内容。
我想出了一个解决方案,可以处理多个标识,每个级别都有可配置的编号规则:
require 'nokogiri'
ROMANS = %w[i ii iii iv v vi vii viii ix]
RULES = {
ol: {
1 => ->(index) { "#{index + 1}. " },
2 => ->(index) { "#{('a'..'z').to_a[index]}. " },
3 => ->(index) { "#{ROMANS.to_a[index]}. " },
4 => ->(index) { "#{ROMANS.to_a[index].upcase}. " }
},
ul: {
1 => ->(_) { "\u2022 " },
2 => ->(_) { "\u25E6 " },
3 => ->(_) { "* " },
4 => ->(_) { "- " },
}
}
def ol_rule(group, deepness: 1)
group.search('> li').each_with_index do |item, i|
prefix = RULES[:ol][deepness].call(i)
item.prepend_child(prefix)
descend(item, deepness + 1)
end
end
def ul_rule(group, deepness: 1)
group.search('> li').each_with_index do |item, i|
prefix = RULES[:ul][deepness].call(i)
item.prepend_child(prefix)
descend(item, deepness + 1)
end
end
def descend(item, deepness)
item.search('> ol').each do |ol|
ol_rule(ol, deepness: deepness)
end
item.search('> ul').each do |ul|
ul_rule(ul, deepness: deepness)
end
end
doc = Nokogiri::HTML.fragment(text)
doc.search('ol:root').each do |group|
binding.pry
ol_rule(group, deepness: 1)
end
doc.search('ul:root').each do |group|
ul_rule(group, deepness: 1)
end
然后您可以删除标签或使用 doc.inner_text,具体取决于您的环境。
但有两个注意事项:
- 必须仔细选择您的条目选择器。我在没有根元素的情况下逐字使用了您的代码段,因此我不得不使用 ul:root/ol:root。也许 "body > ol" 也适用于您的情况。也许选择每个 ol/ul 但不是遍历每个并且只找到那些没有列表父级的。
- 逐字使用您的示例,Nokogiri 不能很好地处理第一组 ol 的最后 2 个列表项("hey","Three") 当用 nokogiri 解析时,元素已经 "left" 它们的 ol 树并被放置在根树中。
当前输出:
1. One
2. Two
a. Inner One
b. inner Two
◦ hey
◦ hey
3. hey
4. hey
hey
Three
1. Introduction
a. Introduction
2. Description
3. Observation
4. Results
5. Summary
• Introduction
• Description
◦ Observation
* Results
- Summary
• Overview
首先为了处理 space,我在 lambda 调用中使用了 hack。 此外,我正在使用 nokogiri 提供的 add_previous_sibling 函数在开始时附加一些内容。最后,当我们处理 ul 和 ol 标签时,Prawn 不处理 space 因此我使用了这个 gsub gsub(/^([^\S\r\n]+)/m) { |米| “\xC2\xA0”*m.size}。您可以阅读更多内容 link
注意:Nokogiri 不处理无效 HTML 所以总是提供有效 HTML
RULES = {
ol: {
1 => ->(index) { "#{index + 1}. " },
2 => ->(index) { "#{}" },
3 => ->(index) { "#{}" },
4 => ->(index) { "#{}" }
},
ul: {
1 => ->(_) { "\u2022 " },
2 => ->(_) { "" },
3 => ->(_) { "" },
4 => ->(_) { "" },
},
space: {
1 => ->(index) { " " },
2 => ->(index) { " " },
3 => ->(index) { " " },
4 => ->(index) { " " },
}
}
def ol_rule(group, deepness: 1)
group.search('> li').each_with_index do |item, i|
prefix = RULES[:ol][deepness].call(i)
space = RULES[:space][deepness].call(i)
item.add_previous_sibling(space)
item.prepend_child(prefix)
descend(item, deepness + 1)
end
end
def ul_rule(group, deepness: 1)
group.search('> li').each_with_index do |item, i|
space = RULES[:space][deepness].call(i)
prefix = RULES[:ul][deepness].call(i)
item.add_previous_sibling(space)
item.prepend_child(prefix)
descend(item, deepness + 1)
end
end
def descend(item, deepness)
item.search('> ol').each do |ol|
ol_rule(ol, deepness: deepness)
end
item.search('> ul').each do |ul|
ul_rule(ul, deepness: deepness)
end
end
doc = Nokogiri::HTML.parse(text)
doc.search('ol').each do |group|
ol_rule(group, deepness: 1)
end
doc.search('ul').each do |group|
ul_rule(group, deepness: 1)
end
Prawn::Document.generate("hello.pdf") do
#puts doc.inner_text
text doc.at('body').children.to_html.gsub(/^([^\S\r\n]+)/m) { |m| "\xC2\xA0" * m.size }.gsub("<ul>","").gsub("<\/ul>","").gsub("<ol>","").gsub("<\/ol>","").gsub("<li>", "").gsub("</li>","").gsub("\n","").gsub(/[\n]+/, "\n")
end