relaton-bib 2.1.7 → 2.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/relaton/bib/sanitizer.rb +139 -3
- data/lib/relaton/bib/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 74bf6a3c3abe13cbadc903c2d2b811b125f654033e092ed33305834663404854
|
|
4
|
+
data.tar.gz: 396420681c9fe3567117b7e6a992c56a0cbfd3b219d36d650d8deb072a36435b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9fdb28c540d26dd47ac56af80c292cae33f6cafa96672161d732f85e457b4a7336c2c5f11d5f5b852284433f73b08cfefe7d2af0c1e2d99e1557c05f985f46da
|
|
7
|
+
data.tar.gz: 1585a8df0f2a2ad420eb26ed1d11a6f36483f90f10510f3cb63f72145d0d401b4499016100475b37195f31033d4c600bd281d8d4f97b7f648732212f7a5378b2
|
|
@@ -42,15 +42,151 @@ module Relaton
|
|
|
42
42
|
|
|
43
43
|
TAG_RX = %r{<[a-zA-Z/!?]}
|
|
44
44
|
|
|
45
|
+
# Captures a namespace prefix, on a tag or on an attribute: the
|
|
46
|
+
# "jats" of <jats:p> and </jats:italic>, and the "xlink" of
|
|
47
|
+
# xlink:href.
|
|
48
|
+
NS_PREFIX_RX = %r{(?:</?|\s)([A-Za-z_][\w.-]*):(?=[A-Za-z_])}
|
|
49
|
+
|
|
50
|
+
# Namespace that declares a prefix which the content leaves
|
|
51
|
+
# undeclared. The sanitiser removes it again before it serialises.
|
|
52
|
+
NS_PLACEHOLDER = "urn:x-relaton-undeclared:%s".freeze
|
|
53
|
+
|
|
54
|
+
# Element that carries the placeholder declarations. Its children
|
|
55
|
+
# are the sanitised content, so the element itself never reaches
|
|
56
|
+
# the output.
|
|
57
|
+
NS_WRAPPER = "relaton-sanitizer-root".freeze
|
|
58
|
+
|
|
59
|
+
# Reserved prefixes. XML declares both, so the content must not.
|
|
60
|
+
NS_RESERVED = %w[xml xmlns].freeze
|
|
61
|
+
|
|
62
|
+
# Serialise without the FORMAT option, so the sanitiser keeps the
|
|
63
|
+
# shape of element-only content instead of adding newlines and
|
|
64
|
+
# indent.
|
|
65
|
+
SAVE_OPTS = Nokogiri::XML::Node::SaveOptions::AS_XML
|
|
66
|
+
|
|
45
67
|
def self.sanitize(content)
|
|
46
68
|
return content unless sanitizable?(content)
|
|
47
69
|
|
|
70
|
+
node = parse(content)
|
|
71
|
+
return content if node.nil?
|
|
72
|
+
|
|
73
|
+
sanitize_children(node)
|
|
74
|
+
node.children.map do |c|
|
|
75
|
+
c.to_xml(encoding: "UTF-8", save_with: SAVE_OPTS)
|
|
76
|
+
end.join
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
#
|
|
80
|
+
# Parse the content into a node whose children are the content.
|
|
81
|
+
#
|
|
82
|
+
# @param [String] content The raw marked-up content.
|
|
83
|
+
#
|
|
84
|
+
# @return [Nokogiri::XML::Node, nil] The node, or nil when the
|
|
85
|
+
# content does not parse.
|
|
86
|
+
#
|
|
87
|
+
def self.parse(content)
|
|
48
88
|
fragment = Nokogiri::XML::DocumentFragment.parse(content)
|
|
49
|
-
return
|
|
89
|
+
return fragment if fragment.errors.empty?
|
|
90
|
+
|
|
91
|
+
parse_with_prefixes(content)
|
|
92
|
+
end
|
|
93
|
+
private_class_method :parse
|
|
50
94
|
|
|
51
|
-
|
|
52
|
-
|
|
95
|
+
#
|
|
96
|
+
# Parse content that uses undeclared namespace prefixes.
|
|
97
|
+
#
|
|
98
|
+
# An undeclared prefix is always a parse error, so without this the
|
|
99
|
+
# sanitiser gives up on exactly the third-party markup that needs
|
|
100
|
+
# sanitising most. Declare every prefix that the content uses on a
|
|
101
|
+
# wrapper element, parse, then remove the placeholder namespaces
|
|
102
|
+
# from the elements and from the attributes. See metanorma-pdfa#99.
|
|
103
|
+
#
|
|
104
|
+
# An undeclared prefix inside an OPAQUE <stem> goes as well. The
|
|
105
|
+
# sanitiser cannot keep it: an undeclared prefix in the output is
|
|
106
|
+
# the exact failure that this method removes. Only a namespace that
|
|
107
|
+
# the content declares itself survives verbatim.
|
|
108
|
+
#
|
|
109
|
+
# @param [String] content The raw marked-up content.
|
|
110
|
+
#
|
|
111
|
+
# @return [Nokogiri::XML::Element, nil] The wrapper element, or nil
|
|
112
|
+
# when the content uses no prefix or does not parse.
|
|
113
|
+
#
|
|
114
|
+
def self.parse_with_prefixes(content)
|
|
115
|
+
decl = placeholder_declarations(content) or return
|
|
116
|
+
name = wrapper_name(content)
|
|
117
|
+
doc = Nokogiri::XML "<#{name} #{decl}>#{content}</#{name}>"
|
|
118
|
+
return unless doc.errors.empty?
|
|
119
|
+
|
|
120
|
+
drop_placeholder_namespaces doc.root
|
|
121
|
+
end
|
|
122
|
+
private_class_method :parse_with_prefixes
|
|
123
|
+
|
|
124
|
+
#
|
|
125
|
+
# Declare every namespace prefix that the content uses.
|
|
126
|
+
#
|
|
127
|
+
# @param [String] content The raw marked-up content.
|
|
128
|
+
#
|
|
129
|
+
# @return [String, nil] The declarations, or nil when the content
|
|
130
|
+
# uses no prefix.
|
|
131
|
+
#
|
|
132
|
+
def self.placeholder_declarations(content)
|
|
133
|
+
prefixes = content.scan(NS_PREFIX_RX).flatten.uniq - NS_RESERVED
|
|
134
|
+
return if prefixes.empty?
|
|
135
|
+
|
|
136
|
+
prefixes.map do |pfx|
|
|
137
|
+
%(xmlns:#{pfx}="#{format NS_PLACEHOLDER, pfx}")
|
|
138
|
+
end.join(" ")
|
|
139
|
+
end
|
|
140
|
+
private_class_method :placeholder_declarations
|
|
141
|
+
|
|
142
|
+
#
|
|
143
|
+
# Name a wrapper element that the content does not close itself.
|
|
144
|
+
#
|
|
145
|
+
# Content that holds the literal end tag of the wrapper would close
|
|
146
|
+
# it early. The document then has more than one root, the parse
|
|
147
|
+
# fails, and the sanitiser gives up on content that it can handle.
|
|
148
|
+
#
|
|
149
|
+
# @param [String] content The raw marked-up content.
|
|
150
|
+
#
|
|
151
|
+
# @return [String] A name that the content does not contain.
|
|
152
|
+
#
|
|
153
|
+
def self.wrapper_name(content)
|
|
154
|
+
name = NS_WRAPPER
|
|
155
|
+
name += "-x" while content.include?(name)
|
|
156
|
+
name
|
|
157
|
+
end
|
|
158
|
+
private_class_method :wrapper_name
|
|
159
|
+
|
|
160
|
+
#
|
|
161
|
+
# Remove the placeholder namespaces, and only those.
|
|
162
|
+
#
|
|
163
|
+
# Nokogiri's remove_namespaces! would also strip a namespace that
|
|
164
|
+
# the content declares itself, such as the MathML xmlns inside an
|
|
165
|
+
# OPAQUE <stem>, which must survive verbatim. Match the wrapper's
|
|
166
|
+
# own declarations, so a namespace of the content never matches,
|
|
167
|
+
# whatever its URI.
|
|
168
|
+
#
|
|
169
|
+
# The declarations stay on the wrapper element. Only its children
|
|
170
|
+
# reach the output, so the declarations never leak. Do not
|
|
171
|
+
# serialise the root itself.
|
|
172
|
+
#
|
|
173
|
+
# @param [Nokogiri::XML::Element] root The wrapper element.
|
|
174
|
+
#
|
|
175
|
+
# @return [Nokogiri::XML::Element] The same element.
|
|
176
|
+
#
|
|
177
|
+
def self.drop_placeholder_namespaces(root)
|
|
178
|
+
placeholders = root.namespace_definitions
|
|
179
|
+
root.traverse do |node|
|
|
180
|
+
node.namespace = nil if placeholders.include?(node.namespace)
|
|
181
|
+
next unless node.element?
|
|
182
|
+
|
|
183
|
+
node.attribute_nodes.each do |attr|
|
|
184
|
+
attr.namespace = nil if placeholders.include?(attr.namespace)
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
root
|
|
53
188
|
end
|
|
189
|
+
private_class_method :drop_placeholder_namespaces
|
|
54
190
|
|
|
55
191
|
def self.sanitizable?(content)
|
|
56
192
|
content.is_a?(::String) && !content.empty? && content.match?(TAG_RX)
|
data/lib/relaton/bib/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: relaton-bib
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.1.
|
|
4
|
+
version: 2.1.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-09-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bibtex-ruby
|