isodoc 1.6.3 → 1.6.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rake.yml +2 -12
  3. data/.hound.yml +3 -1
  4. data/.rubocop.yml +4 -6
  5. data/isodoc.gemspec +3 -2
  6. data/lib/isodoc-yaml/i18n-en.yaml +1 -0
  7. data/lib/isodoc-yaml/i18n-fr.yaml +1 -0
  8. data/lib/isodoc-yaml/i18n-zh-Hans.yaml +1 -0
  9. data/lib/isodoc.rb +0 -2
  10. data/lib/isodoc/convert.rb +7 -1
  11. data/lib/isodoc/function/blocks.rb +5 -4
  12. data/lib/isodoc/function/cleanup.rb +52 -43
  13. data/lib/isodoc/function/inline.rb +7 -7
  14. data/lib/isodoc/function/references.rb +33 -52
  15. data/lib/isodoc/function/section.rb +28 -16
  16. data/lib/isodoc/function/table.rb +21 -22
  17. data/lib/isodoc/function/terms.rb +6 -7
  18. data/lib/isodoc/function/to_word_html.rb +6 -3
  19. data/lib/isodoc/function/utils.rb +181 -163
  20. data/lib/isodoc/gem_tasks.rb +8 -9
  21. data/lib/isodoc/headlesshtml_convert.rb +8 -7
  22. data/lib/isodoc/html_convert.rb +5 -1
  23. data/lib/isodoc/html_function/comments.rb +14 -12
  24. data/lib/isodoc/html_function/footnotes.rb +14 -7
  25. data/lib/isodoc/html_function/html.rb +30 -26
  26. data/lib/isodoc/html_function/postprocess.rb +191 -182
  27. data/lib/isodoc/html_function/sectionsplit.rb +230 -0
  28. data/lib/isodoc/metadata.rb +22 -20
  29. data/lib/isodoc/metadata_contributor.rb +31 -28
  30. data/lib/isodoc/pdf_convert.rb +11 -13
  31. data/lib/isodoc/presentation_function/bibdata.rb +50 -22
  32. data/lib/isodoc/presentation_function/inline.rb +20 -15
  33. data/lib/isodoc/presentation_function/section.rb +38 -1
  34. data/lib/isodoc/presentation_xml_convert.rb +2 -0
  35. data/lib/isodoc/version.rb +1 -1
  36. data/lib/isodoc/word_function/postprocess.rb +50 -36
  37. data/lib/isodoc/xref.rb +2 -0
  38. data/lib/isodoc/xref/xref_gen_seq.rb +60 -35
  39. data/lib/isodoc/xref/xref_sect_gen.rb +4 -4
  40. data/spec/assets/scripts_override.html +3 -0
  41. data/spec/isodoc/blocks_spec.rb +373 -685
  42. data/spec/isodoc/cleanup_spec.rb +40 -42
  43. data/spec/isodoc/i18n_spec.rb +694 -821
  44. data/spec/isodoc/inline_spec.rb +482 -328
  45. data/spec/isodoc/metadata_spec.rb +384 -379
  46. data/spec/isodoc/postproc_spec.rb +163 -55
  47. data/spec/isodoc/presentation_xml_spec.rb +355 -278
  48. data/spec/isodoc/ref_spec.rb +5 -5
  49. data/spec/isodoc/section_spec.rb +216 -199
  50. data/spec/isodoc/sectionsplit_spec.rb +190 -0
  51. data/spec/isodoc/table_spec.rb +41 -42
  52. data/spec/isodoc/terms_spec.rb +84 -84
  53. data/spec/isodoc/xref_spec.rb +974 -932
  54. metadata +22 -5
@@ -0,0 +1,230 @@
1
+ require "metanorma"
2
+ require "yaml"
3
+
4
+ module IsoDoc::HtmlFunction
5
+ module Html
6
+ # assume we pass in Presentation XML, but we want to recover Semantic XML
7
+ def sectionsplit_convert(input_filename, file, debug, output_filename = nil)
8
+ input_filename += ".xml" unless input_filename.match?(/\.xml$/)
9
+ File.exist?(input_filename) or
10
+ File.open(input_filename, "w:UTF-8") { |f| f.write(file) }
11
+ presxml = File.read(input_filename, encoding: "utf-8")
12
+ @openmathdelim, @closemathdelim = extract_delims(presxml)
13
+ xml, filename, dir = convert_init(presxml, input_filename, debug)
14
+ build_collection(xml, presxml, output_filename || filename, dir)
15
+ end
16
+
17
+ def build_collection(xml, presxml, filename, dir)
18
+ base = File.basename(filename)
19
+ collection_setup(base, dir)
20
+ files = sectionsplit(xml, base, dir)
21
+ collection_manifest(base, files, xml, presxml, dir).render(
22
+ format: %i(html), output_folder: "#{filename}_collection",
23
+ coverpage: File.join(dir, "cover.html")
24
+ )
25
+ end
26
+
27
+ def collection_manifest(filename, files, origxml, _presxml, dir)
28
+ File.open(File.join(dir, "#{filename}.html.yaml"), "w:UTF-8") do |f|
29
+ f.write(collectionyaml(files, origxml))
30
+ end
31
+ Metanorma::Collection.parse File.join(dir, "#{filename}.html.yaml")
32
+ end
33
+
34
+ def collection_setup(filename, dir)
35
+ FileUtils.mkdir_p "#{filename}_collection"
36
+ FileUtils.mkdir_p dir
37
+ File.open(File.join(dir, "cover.html"), "w:UTF-8") do |f|
38
+ f.write(coll_cover)
39
+ end
40
+ end
41
+
42
+ def coll_cover
43
+ <<~COVER
44
+ <html>
45
+ <head/>
46
+ <body>
47
+ <h1>{{ doctitle }}</h1>
48
+ <h2>{{ docnumber }}</h2>
49
+ <nav>{{ labels["navigation"] }}</nav>
50
+ </body>
51
+ </html>
52
+ COVER
53
+ end
54
+
55
+ def sectionsplit(xml, filename, dir)
56
+ xref_preprocess(xml)
57
+ out = emptydoc(xml)
58
+ [["//preface/*", "preface"], ["//sections/*", "sections"],
59
+ ["//annex", nil],
60
+ ["//bibliography/*[not(@hidden = 'true')]", "bibliography"],
61
+ ["//indexsect", nil]].each_with_object([]) do |n, ret|
62
+ xml.xpath(ns(n[0])).each do |s|
63
+ ret << sectionfile(out, dir, "#{filename}.#{ret.size}", s, n[1])
64
+ end
65
+ end
66
+ end
67
+
68
+ def emptydoc(xml)
69
+ out = xml.dup
70
+ out.xpath(
71
+ ns("//preface | //sections | //annex | //bibliography/clause | "\
72
+ "//bibliography/references[not(@hidden = 'true')] | //indexsect"),
73
+ ).each(&:remove)
74
+ out
75
+ end
76
+
77
+ def sectionfile(xml, dir, file, chunk, parentnode)
78
+ fname = create_sectionfile(xml.dup, dir, file, chunk, parentnode)
79
+ { order: chunk["displayorder"].to_i, url: fname,
80
+ title: titlerender(chunk) }
81
+ end
82
+
83
+ def create_sectionfile(out, dir, file, chunk, parentnode)
84
+ ins = out.at(ns("//misccontainer")) || out.at(ns("//bibdata"))
85
+ if parentnode
86
+ ins.next = "<#{parentnode}/>"
87
+ ins.next.add_child(chunk.dup)
88
+ else
89
+ ins.next = chunk.dup
90
+ end
91
+ outname = "#{file}.xml"
92
+ File.open(File.join(dir, outname), "w:UTF-8") { |f| f.write(out) }
93
+ outname
94
+ end
95
+
96
+ def xref_preprocess(xml)
97
+ svg_preprocess(xml)
98
+ key = (0...8).map { rand(65..90).chr }.join # random string
99
+ refs = eref_to_internal_eref(xml, key)
100
+ refs += xref_to_internal_eref(xml, key)
101
+ xml.root["type"] = key # to force recognition of internal refs
102
+ insert_indirect_biblio(xml, refs, key)
103
+ end
104
+
105
+ def svg_preprocess(xml)
106
+ xml.xpath("//m:svg", "m" => "http://www.w3.org/2000/svg").each do |s|
107
+ m = svgmap_wrap(s)
108
+ s.xpath(".//m:a", "m" => "http://www.w3.org/2000/svg").each do |a|
109
+ next unless /^#/.match? a["href"]
110
+
111
+ a["href"] = a["href"].sub(/^#/, "")
112
+ m << "<target href='#{a['href']}'>"\
113
+ "<xref target='#{a['href']}'/></target>"
114
+ end
115
+ end
116
+ end
117
+
118
+ def svgmap_wrap(svg)
119
+ ret = svg.at("./ancestor::xmlns:svgmap") and return ret
120
+ ret = svg.at("./ancestor::xmlns:figure")
121
+ ret.wrap("<svgmap/>")
122
+ svg.at("./ancestor::xmlns:svgmap")
123
+ end
124
+
125
+ def make_anchor(anchor)
126
+ "<localityStack><locality type='anchor'><referenceFrom>"\
127
+ "#{anchor}</referenceFrom></locality></localityStack>"
128
+ end
129
+
130
+ def xref_to_internal_eref(xml, key)
131
+ xml.xpath(ns("//xref")).each_with_object({}) do |x, m|
132
+ x["bibitemid"] = "#{key}_#{x['target']}"
133
+ x << make_anchor(x["target"])
134
+ m[x["bibitemid"]] = true
135
+ x.delete("target")
136
+ x["type"] = key
137
+ x.name = "eref"
138
+ end.keys
139
+ end
140
+
141
+ def eref_to_internal_eref(xml, key)
142
+ eref_to_internal_eref_select(xml).each_with_object([]) do |x, m|
143
+ url = xml.at(ns("//bibitem[@id = '#{x}']/url[@type = 'citation']"))
144
+ xml.xpath(("//*[@bibitemid = '#{x}']")).each do |e|
145
+ id = eref_to_internal_eref1(e, key, url)
146
+ id and m << id
147
+ end
148
+ end
149
+ end
150
+
151
+ def eref_to_internal_eref1(elem, key, url)
152
+ if url
153
+ elem.name = "link"
154
+ elem["target"] = url
155
+ nil
156
+ else
157
+ elem["bibitemid"] = "#{key}_#{elem['bibitemid']}"
158
+ elem << make_anchor(elem["bibitemid"])
159
+ elem["type"] = key
160
+ elem["bibitemid"]
161
+ end
162
+ end
163
+
164
+ def eref_to_internal_eref_select(xml)
165
+ refs = xml.xpath(("//*/@bibitemid")).map { |x| x.text } # rubocop:disable Style/SymbolProc
166
+ refs.uniq.reject do |x|
167
+ xml.at(ns("//bibitem[@id = '#{x}'][@type = 'internal']"))
168
+ end
169
+ end
170
+
171
+ # from standoc
172
+ def insert_indirect_biblio(xmldoc, refs, prefix)
173
+ ins = xmldoc.at("bibliography") or
174
+ xmldoc.root << "<bibliography/>" and ins = xmldoc.at("bibliography")
175
+ ins = ins.add_child("<references hidden='true' normative='false'/>").first
176
+ refs.each do |x|
177
+ ins << <<~BIBENTRY
178
+ <bibitem id="#{x}" type="internal">
179
+ <docidentifier type="repository">#{x.sub(/^#{prefix}_/, "#{prefix}/")}</docidentifier>
180
+ </bibitem>
181
+ BIBENTRY
182
+ end
183
+ end
184
+
185
+ def recursive_string_keys(hash)
186
+ case hash
187
+ when Hash then Hash[
188
+ hash.map { |k, v| [k.to_s, recursive_string_keys(v)] }
189
+ ]
190
+ when Enumerable then hash.map { |v| recursive_string_keys(v) }
191
+ else
192
+ hash
193
+ end
194
+ end
195
+
196
+ def titlerender(section)
197
+ title = section.at(ns("./title")) or return "[Untitled]"
198
+ t = title.dup
199
+ t.xpath(ns(".//tab | .//br")).each { |x| x.replace(" ") }
200
+ t.xpath(ns(".//strong")).each { |x| x.replace(x.children) }
201
+ t.children.to_xml
202
+ end
203
+
204
+ def collectionyaml(files, xml)
205
+ ret = {
206
+ directives: ["presentation-xml", "bare-after-first"],
207
+ bibdata: {
208
+ title: {
209
+ type: "title-main",
210
+ language: @lang,
211
+ content: xml.at(ns("//bibdata/title")).text,
212
+ },
213
+ type: "collection",
214
+ docid: {
215
+ type: xml.at(ns("//bibdata/docidentifier/@type")).text,
216
+ id: xml.at(ns("//bibdata/docidentifier")).text,
217
+ },
218
+ },
219
+ manifest: {
220
+ level: "collection",
221
+ title: "Collection",
222
+ docref: files.sort_by { |f| f[:order] }.each.map do |f|
223
+ { fileref: f[:url], identifier: f[:title] }
224
+ end,
225
+ },
226
+ }
227
+ recursive_string_keys(ret).to_yaml
228
+ end
229
+ end
230
+ end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative './metadata_date'
4
- require_relative './metadata_contributor'
3
+ require_relative "./metadata_date"
4
+ require_relative "./metadata_contributor"
5
5
 
6
6
  module IsoDoc
7
7
  class Metadata
@@ -17,7 +17,7 @@ module IsoDoc
17
17
 
18
18
  def initialize(lang, script, i18n, fonts_options = {})
19
19
  @metadata = { lang: lang, script: script }
20
- DATETYPES.each { |w| @metadata["#{w.gsub(/-/, '_')}date".to_sym] = 'XXX' }
20
+ DATETYPES.each { |w| @metadata["#{w.gsub(/-/, '_')}date".to_sym] = "XXX" }
21
21
  @lang = lang
22
22
  @script = script
23
23
  @c = HTMLEntities.new
@@ -38,7 +38,7 @@ module IsoDoc
38
38
  @metadata[key] = value
39
39
  end
40
40
 
41
- NOLANG = "[not(@language) or @language = '']".freeze
41
+ NOLANG = "[not(@language) or @language = '']"
42
42
 
43
43
  def currlang
44
44
  "[@language = '#{@lang}']"
@@ -54,6 +54,7 @@ module IsoDoc
54
54
  def docstatus(xml, _out)
55
55
  set(:unpublished, true)
56
56
  return unless s = xml.at(ns("//bibdata/status/stage#{NOLANG}"))
57
+
57
58
  s1 = xml.at(ns("//bibdata/status/stage#{currlang}")) || s
58
59
  set(:stage, status_print(s.text))
59
60
  s1 and set(:stage_display, status_print(s1.text))
@@ -61,26 +62,26 @@ module IsoDoc
61
62
  set(:substage, i)
62
63
  (i1 = xml&.at(ns("//bibdata/status/substage#{currlang}"))&.text || i) and
63
64
  set(:substage_display, i1)
64
- (i2 = xml&.at(ns('//bibdata/status/iteration'))&.text) and
65
+ (i2 = xml&.at(ns("//bibdata/status/iteration"))&.text) and
65
66
  set(:iteration, i2)
66
67
  set(:unpublished, unpublished(s.text))
67
68
  unpublished(s.text) && set(:stageabbr, stage_abbr(s.text))
68
69
  end
69
70
 
70
71
  def stage_abbr(docstatus)
71
- status_print(docstatus).split(/ /).map { |s| s[0].upcase }.join('')
72
+ status_print(docstatus).split(/ /).map { |s| s[0].upcase }.join("")
72
73
  end
73
74
 
74
75
  def unpublished(status)
75
- !status.casecmp('published').zero?
76
+ !status.casecmp("published").zero?
76
77
  end
77
78
 
78
79
  def status_print(status)
79
- status.split(/[- ]/).map(&:capitalize).join(' ')
80
+ status.split(/[- ]/).map(&:capitalize).join(" ")
80
81
  end
81
82
 
82
83
  def docid(isoxml, _out)
83
- dn = isoxml.at(ns('//bibdata/docidentifier'))
84
+ dn = isoxml.at(ns("//bibdata/docidentifier"))
84
85
  set(:docnumber, dn&.text)
85
86
  end
86
87
 
@@ -92,23 +93,24 @@ module IsoDoc
92
93
  end
93
94
 
94
95
  def docnumeric(isoxml, _out)
95
- dn = isoxml.at(ns('//bibdata/docnumber'))
96
+ dn = isoxml.at(ns("//bibdata/docnumber"))
96
97
  set(:docnumeric, dn&.text)
97
98
  end
98
99
 
99
100
  def draftinfo(draft, revdate)
100
101
  return "" unless draft
102
+
101
103
  draftinfo = " (#{@labels['draft_label']} #{draft}"
102
104
  draftinfo += ", #{revdate}" if revdate
103
- draftinfo += ')'
105
+ draftinfo += ")"
104
106
  l10n(draftinfo, @lang, @script)
105
107
  end
106
108
 
107
109
  def version(isoxml, _out)
108
- set(:edition, isoxml&.at(ns('//bibdata/edition'))&.text)
109
- set(:docyear, isoxml&.at(ns('//bibdata/copyright/from'))&.text)
110
- set(:draft, isoxml&.at(ns('//version/draft'))&.text)
111
- revdate = isoxml&.at(ns('//version/revision-date'))&.text
110
+ set(:edition, isoxml&.at(ns("//bibdata/edition"))&.text)
111
+ set(:docyear, isoxml&.at(ns("//bibdata/copyright/from"))&.text)
112
+ set(:draft, isoxml&.at(ns("//bibdata/version/draft"))&.text)
113
+ revdate = isoxml&.at(ns("//bibdata/version/revision-date"))&.text
112
114
  set(:revdate, revdate)
113
115
  set(:revdate_monthyear, monthyr(revdate))
114
116
  set(:draftinfo,
@@ -131,20 +133,20 @@ module IsoDoc
131
133
 
132
134
  def relations_partof(isoxml)
133
135
  std = isoxml.at(ns("//bibdata/relation[@type = 'partOf']")) || return
134
- id = std.at(ns('.//docidentifier'))
136
+ id = std.at(ns(".//docidentifier"))
135
137
  set(:partof, id.text) if id
136
138
  end
137
139
 
138
140
  def relations_obsoletes(isoxml)
139
141
  std = isoxml.at(ns("//bibdata/relation[@type = 'obsoletes']")) || return
140
- locality = std.at(ns('.//locality'))
141
- id = std.at(ns('.//docidentifier'))
142
+ locality = std.at(ns(".//locality"))
143
+ id = std.at(ns(".//docidentifier"))
142
144
  set(:obsoletes, id.text) if id
143
145
  set(:obsoletes_part, locality.text) if locality
144
146
  end
145
147
 
146
148
  def url(xml, _out)
147
- (a = xml.at(ns('//bibdata/uri[not(@type)]'))) && set(:url, a.text)
149
+ (a = xml.at(ns("//bibdata/uri[not(@type)]"))) && set(:url, a.text)
148
150
  (a = xml.at(ns("//bibdata/uri[@type = 'html']"))) && set(:html, a.text)
149
151
  (a = xml.at(ns("//bibdata/uri[@type = 'xml']"))) && set(:xml, a.text)
150
152
  (a = xml.at(ns("//bibdata/uri[@type = 'pdf']"))) && set(:pdf, a.text)
@@ -153,7 +155,7 @@ module IsoDoc
153
155
 
154
156
  def keywords(isoxml, _out)
155
157
  ret = []
156
- isoxml.xpath(ns('//bibdata/keyword')).each { |kw| ret << kw.text }
158
+ isoxml.xpath(ns("//bibdata/keyword")).each { |kw| ret << kw.text }
157
159
  set(:keywords, ret)
158
160
  end
159
161
 
@@ -2,26 +2,29 @@ module IsoDoc
2
2
  class Metadata
3
3
  def extract_person_names(authors)
4
4
  authors.reduce([]) do |ret, a|
5
- if a.at(ns('./name/completename'))
6
- ret << a.at(ns('./name/completename')).text
5
+ if a.at(ns("./name/completename"))
6
+ ret << a.at(ns("./name/completename")).text
7
7
  else
8
- fn = []
9
- forenames = a.xpath(ns('./name/forename'))
10
- forenames.each { |f| fn << f.text }
11
- surname = a&.at(ns('./name/surname'))&.text
12
- ret << fn.join(' ') + ' ' + surname
8
+ forenames = a.xpath(ns("./name/forename"))
9
+ fn = forenames.each_with_object([]) { |f, m| m << f.text }
10
+ surname = a&.at(ns("./name/surname"))&.text
11
+ ret << "#{fn.join(' ')} #{surname}"
13
12
  end
14
13
  end
15
14
  end
16
15
 
17
16
  def extract_person_affiliations(authors)
18
17
  authors.reduce([]) do |m, a|
19
- name = a&.at(ns('./affiliation/organization/name'))&.text
20
- subdivs = a&.xpath(ns('./affiliation/organization/subdivision'))&.map(&:text)&.join(", ")
21
- name and subdivs and !subdivs.empty? and name = l10n("#{name}, #{subdivs}", @lang, @script)
22
- location = a&.at(ns('./affiliation/organization/address/formattedAddress'))&.text
23
- m << (!name.nil? && !location.nil? ? l10n("#{name}, #{location}", @lang, @script) :
24
- (name || location || ''))
18
+ name = a&.at(ns("./affiliation/organization/name"))&.text
19
+ subdivs = a&.xpath(ns("./affiliation/organization/subdivision"))&.map(&:text)&.join(", ")
20
+ name and subdivs and !subdivs.empty? and
21
+ name = l10n("#{name}, #{subdivs}", @lang, @script)
22
+ location = a&.at(ns("./affiliation/organization/address/formattedAddress"))&.text
23
+ m << (if !name.nil? && !location.nil?
24
+ l10n("#{name}, #{location}", @lang, @script)
25
+ else
26
+ (name || location || "")
27
+ end)
25
28
  m
26
29
  end
27
30
  end
@@ -50,19 +53,19 @@ module IsoDoc
50
53
  end
51
54
 
52
55
  def iso?(org)
53
- name = org&.at(ns('./name'))&.text
54
- abbrev = org&.at(ns('./abbreviation'))&.text
55
- (abbrev == 'ISO' ||
56
- name == 'International Organization for Standardization')
56
+ name = org&.at(ns("./name"))&.text
57
+ abbrev = org&.at(ns("./abbreviation"))&.text
58
+ (abbrev == "ISO" ||
59
+ name == "International Organization for Standardization")
57
60
  end
58
61
 
59
62
  def agency1(xml)
60
- agency = ''
63
+ agency = ""
61
64
  publisher = []
62
65
  xml.xpath(ns("//bibdata/contributor[xmlns:role/@type = 'publisher']/"\
63
- 'organization')).each do |org|
64
- name = org&.at(ns('./name'))&.text
65
- agency1 = org&.at(ns('./abbreviation'))&.text || name
66
+ "organization")).each do |org|
67
+ name = org&.at(ns("./name"))&.text
68
+ agency1 = org&.at(ns("./abbreviation"))&.text || name
66
69
  publisher << name if name
67
70
  agency = iso?(org) ? "ISO/#{agency}" : "#{agency}#{agency1}/"
68
71
  end
@@ -71,21 +74,21 @@ module IsoDoc
71
74
 
72
75
  def agency(xml)
73
76
  agency, publisher = agency1(xml)
74
- set(:agency, agency.sub(%r{/$}, ''))
75
- set(:publisher, @i18n.multiple_and(publisher, @labels['and']))
77
+ set(:agency, agency.sub(%r{/$}, ""))
78
+ set(:publisher, @i18n.multiple_and(publisher, @labels["and"]))
76
79
  agency_addr(xml)
77
80
  end
78
81
 
79
82
  def agency_addr(xml)
80
83
  a = xml.at(ns("//bibdata/contributor[xmlns:role/@type = 'publisher'][1]/"\
81
84
  "organization")) or return
82
- n = a.at(ns("./subdivision")) and set(:subdivision, n.text)
85
+ { subdivision: "./subdivision", pub_phone: "./phone[not(@type = 'fax')]",
86
+ pub_fax: "./phone[@type = 'fax']", pub_email: "./email",
87
+ pub_uri: "./uri" }.each do |k, v|
88
+ n = a.at(ns(v)) and set(k, n.text)
89
+ end
83
90
  n = a.at(ns("./address/formattedAddress")) and
84
91
  set(:pub_address, n.children.to_xml)
85
- n = a.at(ns("./phone[not(@type = 'fax')]")) and set(:pub_phone, n.text)
86
- n = a.at(ns("./phone[@type = 'fax']")) and set(:pub_fax, n.text)
87
- n = a.at(ns("./email")) and set(:pub_email, n.text)
88
- n = a.at(ns("./uri")) and set(:pub_uri, n.text)
89
92
  end
90
93
  end
91
94
  end