class Asciidoctor::Gb::Converter

A {Converter} implementation that generates GB output, and a document schema encapsulation of the document for validation

A {Converter} implementation that generates GB output, and a document schema encapsulation of the document for validation

Constants

DATETYPES
GBCODE
HAN_TEXT
ISO_REF
ISO_REF_ALL_PARTS
ISO_REF_NO_YEAR
LOCALISED_ELEMS
MUST_LOCALISE_ELEMS
ROMAN_TEXT

Public Instance Methods

bilingual_terms_validate(root) click to toggle source
# File lib/asciidoctor/gb/validate.rb, line 63
def bilingual_terms_validate(root)
  root.xpath("//term").each do |t|
    check_bilingual(t, "preferred")
    check_bilingual(t, "admitted")
    check_bilingual(t, "deprecates")
  end
end
check_bilingual(t, element) click to toggle source
# File lib/asciidoctor/gb/validate.rb, line 54
def check_bilingual(t, element)
  zh = t.at(".//#{element}[@language = 'zh']")
  en = t.at(".//#{element}[@language = 'en']")
  (en.nil? || en.text.empty?) && !(zh.nil? || zh.text.empty?) &&
    warn("GB: #{element} term #{zh.text} has no English counterpart")
  !(en.nil? || en.text.empty?) && (zh.nil? || zh.text.empty?) &&
    warn("GB: #{element} term #{en.text} has no Chinese counterpart")
end
cleanup(xmldoc) click to toggle source
Calls superclass method
# File lib/asciidoctor/gb/converter.rb, line 209
def cleanup(xmldoc)
  lang = xmldoc.at("//language")&.text
  @agencyclass = GbAgencies::Agencies.new(lang, {}, "")
  super
  contributor_cleanup(xmldoc)
  xmldoc
end
content_validate(doc) click to toggle source
Calls superclass method
# File lib/asciidoctor/gb/validate.rb, line 11
def content_validate(doc)
  super
  bilingual_terms_validate(doc.root)
  issuer_validate(doc.root)
  prefix_validate(doc.root)
  @agencyclass.gbtype_validate(doc.root.at("//gbscope")&.text, doc.root.at("//gbprefix")&.text)
end
contributor_cleanup(xmldoc) click to toggle source
# File lib/asciidoctor/gb/converter.rb, line 226
def contributor_cleanup(xmldoc)
  issuer = xmldoc.at("//bibdata/contributor[role/@type = 'issuer']/organization/name")
  scope = xmldoc.at("//gbscope")&.text
  prefix = xmldoc.at("//gbprefix")&.text
  mandate = xmldoc.at("//gbmandate")&.text || "mandatory"
  agency = issuer.content
  agency = @agencyclass.standard_agency1(scope, prefix, mandate) if agency == "GB"
  agency = "GB" if agency.nil? || agency.empty?
  owner = xmldoc.at("//copyright/owner/organization/name")
  owner.content = agency
  owner = xmldoc.at("//contributor[role/@type = 'issuer']/organization/name")
  owner.content = agency
  xmldoc.xpath("//gbcommittee").each do |c|
    xmldoc.at("//bibdata/contributor").next =
      "<contributor><role type='technical-committee'/><organization>"\
      "<name>#{c.text}</name></organization></contributor>"
  end
end
doc_converter(node) click to toggle source
# File lib/asciidoctor/gb/converter.rb, line 70
def doc_converter(node)
  node.nil? ? IsoDoc::Gb::WordConvert.new({}) :
    IsoDoc::Gb::WordConvert.new(
      script: node.attr("script"),
      bodyfont: node.attr("body-font"),
      headerfont: node.attr("header-font"),
      monospacefont: node.attr("monospace-font"),
      titlefont: node.attr("title-font"),
      i18nyaml: node.attr("i18nyaml"),
      scope: node.attr("scope"),
      wordstylesheet: node.attr("wordstylesheet"),
      standardstylesheet: node.attr("standardstylesheet"),
      header: node.attr("header"),
      wordcoverpage: node.attr("wordcoverpage"),
      wordintropage: node.attr("wordintropage"),
      ulstyle: node.attr("ulstyle"),
      olstyle: node.attr("olstyle"),
  )
end
docidentifier_cleanup(xmldoc) click to toggle source
# File lib/asciidoctor/gb/converter.rb, line 217
def docidentifier_cleanup(xmldoc)
  id = xmldoc.at("//bibdata/docidentifier/project-number") or return
  scope = xmldoc.at("//gbscope")&.text
  prefix = xmldoc.at("//gbprefix")&.text
  mandate = xmldoc.at("//gbmandate")&.text || "mandatory"
  idtext = @agencyclass.docidentifier(scope, prefix, mandate, nil, id.text) || return
  id.content = idtext.gsub(/\&#x2002;/, " ")
end
document(node) click to toggle source
# File lib/asciidoctor/gb/converter.rb, line 90
def document(node)
  init(node)
  ret = makexml(node).to_xml(indent: 2)
  unless node.attr("nodoc") || !node.attr("docfile")
    filename = node.attr("docfile").gsub(/\.adoc$/, "").gsub(%r{^.*/}, "")
    File.open(filename + ".xml", "w") { |f| f.write(ret) }
    html_compliant_converter(node).convert(filename + ".xml")
    system "mv #{filename}.html #{filename}_compliant.html"
    html_converter(node).convert(filename + ".xml")
    doc_converter(node).convert(filename + ".xml")
  end
  @files_to_delete.each { |f| system "rm #{f}" }
  ret
end
duplicate_localisedstrings(zh) click to toggle source
# File lib/asciidoctor/gb/converter.rb, line 140
def duplicate_localisedstrings(zh)
  en = zh.dup.remove
  zh.after(en).after(" ")
  zh["language"] = "zh"
  en["language"] = "en"
  en.traverse do |c|
    c.text? && c.content = c.text.gsub(HAN_TEXT, "").gsub(/^\s*/, "")
  end
  zh.traverse do |c|
    c.text? && c.content = c.text.gsub(ROMAN_TEXT, "").gsub(/^\s*/, "")
  end
end
extract_localisedstrings(elem) click to toggle source

element consists solely of localised strings, with no attributes

# File lib/asciidoctor/gb/converter.rb, line 133
def extract_localisedstrings(elem)
  elem.xpath("./string").each do |s|
    s.name = elem.name
  end
  elem.replace(elem.children)
end
fetch_ref(xml, code, year, **opts) click to toggle source
# File lib/asciidoctor/gb/converter.rb, line 199
def fetch_ref(xml, code, year, **opts)
  code = "GB Standard " + code if /^#{GBCODE}[^A-Za-z]/.match? code
  hit = @bibdb&.fetch(code, year, opts)
  return nil if hit.nil?
  xml.parent.add_child(hit.to_xml)
  xml
rescue Algolia::AlgoliaProtocolError
  nil # Render reference without an Internet connection.
end
front(node, xml) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 12
def front(node, xml)
  xml.bibdata **attr_code(type: standard_type(node)) do |b|
    metadata node, b
  end
  metadata_version(node, xml)
end
get_mandate(node) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 116
def get_mandate(node)
  node.attr("mandate") and return node.attr("mandate")
  p = node.attr("prefix")
  mandate = %r{/T}.match?(p) ? "recommended" :
    %r{/Z}.match?(p) ? "guidelines" : nil
  if mandate.nil?
    mandate = "mandatory"
    warn "GB: no mandate supplied, defaulting to mandatory"
  end
  mandate
end
get_prefix(node) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 102
def get_prefix(node)
  scope = get_scope(node)
  if prefix = node.attr("prefix")
    prefix.gsub!(%r{/[TZ]$}, "")
    prefix.gsub!(%r{^[TQ]/([TZ]/)?}, "")
    prefix.gsub!(/^DB/, "") if scope == "local"
  else
    prefix = "GB"
    scope = "national"
    warn "GB: no prefix supplied, defaulting to GB"
  end
  [scope, prefix]
end
get_scope(node) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 90
def get_scope(node)
  node.attr("scope") and return node.attr("scope")
  scope = if %r{^[TQ]/}.match? node.attr("prefix")
            m = node.attr("prefix").split(%{/})
            mandate = m[0] == "T" ? "social-group" :
              m[0] == "Q" ? "enterprise" : nil
          end
  return scope unless scope.nil?
  warn "GB: no scope supplied, defaulting to National"
  "national"
end
get_topic(node) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 128
def get_topic(node)
  node.attr("topic") and return node.attr("topic")
  warn "GB: no topic supplied, defaulting to basic"
  "basic"
end
html_compliant_converter(node) click to toggle source
# File lib/asciidoctor/gb/converter.rb, line 52
def html_compliant_converter(node)
  node.nil? ? IsoDoc::Gb::HtmlConvert.new({}) :
    IsoDoc::Gb::HtmlConvert.new(
      script: node.attr("script"),
      bodyfont: node.attr("body-font"),
      headerfont: node.attr("header-font"),
      monospacefont: node.attr("monospace-font"),
      titlefont: node.attr("title-font"),
      i18nyaml: node.attr("i18nyaml"),
      scope: node.attr("scope"),
      compliant: true,
      htmlstylesheet: node.attr("htmlstylesheet"),
      htmlcoverpage: node.attr("htmlcoverpage"),
      htmlintropage: node.attr("htmlintropage"),
      scripts: node.attr("scripts"),
  )
end
html_converter(node) click to toggle source
# File lib/asciidoctor/gb/converter.rb, line 35
def html_converter(node)
  node.nil? ? IsoDoc::Gb::HtmlConvert.new({}) :
    IsoDoc::Gb::HtmlConvert.new(
      script: node.attr("script"),
      bodyfont: node.attr("body-font"),
      headerfont: node.attr("header-font"),
      monospacefont: node.attr("monospace-font"),
      titlefont: node.attr("title-font"),
      i18nyaml: node.attr("i18nyaml"),
      scope: node.attr("scope"),
      htmlstylesheet: node.attr("htmlstylesheet"),
      htmlcoverpage: node.attr("htmlcoverpage"),
      htmlintropage: node.attr("htmlintropage"),
      scripts: node.attr("scripts"),
  )
end
inline_quoted(node) click to toggle source
Calls superclass method
# File lib/asciidoctor/gb/converter.rb, line 153
def inline_quoted(node)
  ret = noko do |xml|
    case node.role
    when "en" then xml.string node.text, **{ language: "en" }
    when "zh" then xml.string node.text, **{ language: "zh" }
    when "zh-Hans"
      xml.string node.text, **{ language: "zh", script: "Hans" }
    when "zh-Hant"
      xml.string node.text, **{ language: "zh", script: "Hant" }
    else
      nil
    end
  end.join
  return ret unless ret.nil? or ret.empty?
  super
end
issuer_validate(root) click to toggle source
# File lib/asciidoctor/gb/validate.rb, line 45
def issuer_validate(root)
  issuer = root&.at("//bibdata/contributor[role/@type = 'issuer']/"\
                    "organization/name")&.text
  scope = root&.at("//gbscope")&.text
  if %w(enterprise social).include?(scope) && issuer == "GB"
    warn "No issuer provided for #{scope} standard"
  end
end
localisedstr(xmldoc) click to toggle source
# File lib/asciidoctor/gb/converter.rb, line 122
def localisedstr(xmldoc)
  xmldoc.xpath(LOCALISED_ELEMS).each do |zh|
    if zh.at("./string")
      extract_localisedstrings(zh)
    elsif MUST_LOCALISE_ELEMS.include? zh.name
      duplicate_localisedstrings(zh)
    end
  end
end
makexml(node) click to toggle source
# File lib/asciidoctor/gb/converter.rb, line 21
def makexml(node)
  result = ["<?xml version='1.0' encoding='UTF-8'?>\n<gb-standard>"]
  @draft = node.attributes.has_key?("draft")
  @keepboilerplate = node.attributes.has_key?("keep-boilerplate")
  result << noko { |ixml| front node, ixml }
  result << noko { |ixml| middle node, ixml }
  result << "</gb-standard>"
  result = textcleanup(result.flatten * "\n")
  ret1 = cleanup(Nokogiri::XML(result))
  validate(ret1)
  ret1.root.add_namespace(nil, GB_NAMESPACE)
  ret1
end
metadata(node, xml) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 179
def metadata(node, xml)
  title node, xml
  metadata_id(node, xml)
  metadata_date(node, xml)
  metadata_contributors(node, xml)
  xml.language (node.attr("language") || "zh")
  xml.script (node.attr("script") || "Hans")
  metadata_status(node, xml)
  metadata_copyright(node, xml)
  metadata_equivalence(node, xml)
  metadata_obsoletes(node, xml)
  metadata_ics(node, xml)
  metadata_committee(node, xml)
  metadata_gbtype(node, xml)
  metadata_gblibraryids(node, xml)
end
metadata_author(node, xml) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 19
def metadata_author(node, xml)
  author = node.attr("author") || return
  author.split(/, ?/).each do |author|
    xml.contributor do |c|
      c.role **{ type: "author" }
      c.person do |p|
        p.name do |n|
          n.surname author
        end
      end
    end
  end
end
metadata_committee(node, xml) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 57
def metadata_committee(node, xml)
  attrs = { type: node.attr("technical-committee-type") }
  xml.gbcommittee **attr_code(attrs) do |a|
    a << node.attr("technical-committee")
  end
end
metadata_contributor1(node, xml, type, role) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 33
def metadata_contributor1(node, xml, type, role)
  contrib = node.attr(type) || "GB"
  contrib.split(/, ?/).each do |c|
    xml.contributor do |x|
      x.role **{ type: role }
      x.organization do |a|
        a.name { |n| n << c }
      end
    end
  end
end
metadata_contributors(node, xml) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 170
def metadata_contributors(node, xml)
  metadata_author(node, xml)
  metadata_contributor1(node, xml, "author-committee", "author")
  metadata_contributor1(node, xml, "publisher", "publisher")
  metadata_contributor1(node, xml, "authority", "authority")
  metadata_contributor1(node, xml, "proposer", "proposer")
  metadata_contributor1(node, xml, "issuer", "issuer")
end
metadata_date(node, xml) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 155
def metadata_date(node, xml)
  DATETYPES.each do |t|
    metadata_date1(node, xml, t)
  end
end
metadata_date1(node, xml, type) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 144
def metadata_date1(node, xml, type)
  date = node.attr("#{type}-date")
  date and xml.date **{ type: type } do |d|
    d.on date
  end
end
metadata_equivalence(node, xml) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 64
def metadata_equivalence(node, xml)
  isostd = node.attr("iso-standard") || return
  type = node.attr("equivalence") || "equivalent"
  m = /^(?<code>[^,]+),?(?<title>.*)$/.match isostd
  title = m[:title].empty? ? "[not supplied]" : m[:title]
  xml.relation **{ type: type } do |r|
    r.bibitem do |b|
      b.title { |t| t << title }
      b.docidentifier m[:code]
    end
  end
end
metadata_gblibraryids(node, xml) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 161
def metadata_gblibraryids(node, xml)
  ccs = node.attr("library-ccs")
  ccs and ccs.split(/, ?/).each do |l|
    xml.ccs { |c| c << l }
  end
  l = node.attr("library-plan")
  l && xml.plannumber { |plan| plan << l }
end
metadata_gbtype(node, xml) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 134
def metadata_gbtype(node, xml)
  xml.gbtype do |t|
    scope, prefix = get_prefix(node)
    t.gbscope { |s| s << scope }
    t.gbprefix { |p| p << prefix }
    t.gbmandate { |m| m << get_mandate(node) }
    t.gbtopic { |t| t << get_topic(node) }
  end
end
metadata_obsoletes(node, xml) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 77
def metadata_obsoletes(node, xml)
  std = node.attr("obsoletes") || return
  m = /^(?<code>[^,]+),?(?<title>.*)$/.match std
  title = m[:title].empty? ? "[not supplied]" : m[:title]
  xml.relation **{ type: "obsoletes" } do |r|
    r.bibitem do |b|
      b.title { |t| t << title }
      b.docidentifier m[:code]
    end
    r.bpart node.attr("obsoletes-parts") if node.attr("obsoletes-parts")
  end
end
norm_bibitem_style(root) click to toggle source
# File lib/asciidoctor/gb/validate.rb, line 104
def norm_bibitem_style(root)
  root.xpath(NORM_BIBITEMS).each do |b|
    if b.at(Asciidoctor::Standoc::Converter::ISO_PUBLISHER_XPATH).nil?
      unless /^#{GBCODE}(?![A-Z])/.match? b.at("./docidentifier").text
        Asciidoctor::Standoc::Utils::warning(b, NORM_ISO_WARN, b.text)
      end
    end
  end
end
prefix_validate(root) click to toggle source
# File lib/asciidoctor/gb/validate.rb, line 19
def prefix_validate(root)
  prefix = root&.at("//gbprefix")&.text
  scope = root&.at("//gbscope")&.text
  case scope
  when "social-group"
    /^[A-Za-z]{3,6}$/.match? prefix or
      warn("#{prefix} is improperly formatted for social standards")
  when "enterprise"
    /^[A-Z0-9]{3,}$/.match? prefix or
      warn("#{prefix} is improperly formatted for enterprise standards")
  when "sector"
    %w(AQ BB CB CH CJ CY DA DB DL DZ EJ FZ GA GH GM GY HB HG HJ HS HY
       JB JC JG JR JT JY LB LD LS LY MH MT MZ NY QB QC QJ QX SB SC SH
       SJ SL SN SY TB TD TJ TY WB WH WJ WM WS WW XB YB YC YD YS YY YZ
       ZY).include? prefix or
       warn("#{prefix} is not a legal sector standard prefix")
  when "local"
    %w(11 12 13 14 15 21 22 23 31 32 33 34 35 36 37 41 42 43 44 45 46
       50 51 52 53 54 61 62 63 64 65 71 81 82 end).include? prefix or
       warn("#{prefix} is not a legal local standard prefix")
  when "national"
    %w(GB GBZ GJB GBn GHZB GWPB JJF JJG).include? prefix or
      warn("#{prefix} is not a legal national standard prefix")
  end
end
reference1_matches(item) click to toggle source
# File lib/asciidoctor/gb/converter.rb, line 192
def reference1_matches(item)
  matched = ISO_REF.match item
  matched2 = ISO_REF_NO_YEAR.match item
  matched3 = ISO_REF_ALL_PARTS.match item
  [matched, matched2, matched3]
end
section(node) click to toggle source
# File lib/asciidoctor/gb/section_input.rb, line 23
def section(node)
  a = { id: Asciidoctor::Standoc::Utils::anchor_or_uuid(node) }
  noko do |xml|
    case sectiontype(node)
    when "引言", "introduction" then
      if node.level == 1 then introduction_parse(a, xml, node)
      else
        clause_parse(a, xml, node)
      end
    when "patent notice" then patent_notice_parse(xml, node)
    when "范围", "scope" then scope_parse(a, xml, node)
    when "规范性引用文件", "normative references"
      norm_ref_parse(a, xml, node)
    when "术语和定义", "terms and definitions",
      "术语、定义、符号、代号和缩略语",
      "terms, definitions, symbols and abbreviated terms"
      @term_def = true
      term_def_parse(a, xml, node, true)
      @term_def = false
    when "符号、代号和缩略语", "symbols and abbreviated terms"
      symbols_parse(a, xml, node)
    when "参考文献", "bibliography"
      bibliography_parse(a, xml, node)
    else
      if @term_def then term_def_subclause_parse(a, xml, node)
      elsif @biblio then bibliography_parse(a, xml, node)
                    elsif node.attr("style") == "bibliography" && node.level == 1
        bibliography_parse(a, xml, node)
      elsif node.attr("style") == "appendix" && node.level == 1
        annex_parse(a, xml, node)
      else
        clause_parse(a, xml, node)
      end
    end
  end.join("\n")
end
standard_type(node) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 5
def standard_type(node)
  type = node.attr("mandate") || "mandatory"
  type = "standard" if type == "mandatory"
  type = "recommendation" if type == "recommended"
  type
end
term_def_subclause_parse(attrs, xml, node) click to toggle source
# File lib/asciidoctor/gb/section_input.rb, line 10
def term_def_subclause_parse(attrs, xml, node)
  # subclause contains subclauses
  sub = node.find_by(context: :section) {|s| s.level == node.level + 1 }
  sub.empty? || (return term_def_parse(attrs, xml, node, false))
  (node.title.downcase == "symbols and abbreviated terms" ||
  node.title == "符号、代号和缩略语") &&
    (return symbols_parse(attrs, xml, node))
  xml.term **attr_code(attrs) do |xml_section|
    xml_section.preferred { |name| name << node.title }
    xml_section << node.content
  end
end
termdef_boilerplate_cleanup(xmldoc) click to toggle source
Calls superclass method
# File lib/asciidoctor/gb/converter.rb, line 170
def termdef_boilerplate_cleanup(xmldoc)
  return if @keepboilerplate
  super
end
termdef_cleanup(xmldoc) click to toggle source
Calls superclass method
# File lib/asciidoctor/gb/converter.rb, line 105
def termdef_cleanup(xmldoc)
  super
  localisedstr(xmldoc)
end
title(node, xml) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 216
def title(node, xml)
  ["en", "zh"].each do |lang|
    xml.title do |t|
      at = { language: lang, format: "plain" }
      title_intro(node, lang, t, at)
      title_main(node, lang, t, at)
      title_part(node, lang, t, at)
    end
  end
end
title_intro(node, lang, t, at) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 196
def title_intro(node, lang, t, at)
  node.attr("title-intro-#{lang}") and
    t.title_intro **attr_code(at) do |t1|
    t1 << asciidoc_sub(node.attr("title-intro-#{lang}"))
  end
end
title_intro_validate(root) click to toggle source
# File lib/asciidoctor/gb/validate.rb, line 71
def title_intro_validate(root)
  title_intro_en = root.at("//title-intro[@language='en']")
  title_intro_zh = root.at("//title-intro[@language='zh']")
  if title_intro_en.nil? && !title_intro_zh.nil?
    warn "No English Title Intro!"
  end
  if !title_intro_en.nil? && title_intro_zh.nil?
    warn "No Chinese Title Intro!"
  end
end
title_main(node, lang, t, at) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 203
def title_main(node, lang, t, at)
  t.title_main **attr_code(at) do |t1|
    t1 << asciidoc_sub(node.attr("title-main-#{lang}"))
  end
end
title_main_validate(root) click to toggle source
# File lib/asciidoctor/gb/validate.rb, line 82
def title_main_validate(root)
  title_main_en = root.at("//title-main[@language='en']")
  title_main_zh = root.at("//title-main[@language='zh']")
  if title_main_en.nil? && !title_main_zh.nil?
    warn "No English Title!"
  end
  if !title_main_en.nil? && title_main_zh.nil?
    warn "No Chinese Title!"
  end
end
title_part(node, lang, t, at) click to toggle source
# File lib/asciidoctor/gb/front.rb, line 209
def title_part(node, lang, t, at)
  node.attr("title-part-#{lang}") and
    t.title_part **attr_code(at) do |t1|
    t1 << asciidoc_sub(node.attr("title-part-#{lang}"))
  end
end
title_part_validate(root) click to toggle source
# File lib/asciidoctor/gb/validate.rb, line 93
def title_part_validate(root)
  title_part_en = root.at("//title-part[@language='en']")
  title_part_zh = root.at("//title-part[@language='zh']")
  if title_part_en.nil? && !title_part_zh.nil?
    warn "No English Title Part!"
  end
  if !title_part_en.nil? && title_part_zh.nil?
    warn "No Chinese Title Part!"
  end
end
validate(doc) click to toggle source
# File lib/asciidoctor/gb/validate.rb, line 5
def validate(doc)
  content_validate(doc)
  schema_validate(formattedstr_strip(doc.dup),
                  File.join(File.dirname(__FILE__), "gbstandard.rng"))
end