Purpose

The sts Ruby gem allows you to work with NISO STS and ISOSTS documents — two related XML formats for technical standards documents.

  • NISO STS (NISO Z39.96) — The standardized NISO format for journal and article publishing

  • ISOSTS — The internal precursor format to NISO STS, used by ISO before NISO standardization. ISOSTS adopts TBX (ISO 30042) for terminology markup.

Note
This is a work-in-progress.

Formats Compared

Aspect NISO STS ISOSTS

Standard

NISO Z39.96 (NISO standard)

Internal format (pre-NISO standardization)

History

Standardized version

Original internal format, predates NISO STS

Root element

<article>, <book>

<standard>

Metadata

article-meta, journal-meta

iso-meta, reg-meta, nat-meta

MathML version

3+ (via mml gem)

2 (custom Ruby implementation)

Math elements

mml:math + tex-math

mml:math only

Terminology

Inline TBX elements

term-sec with tbx:termEntry

Standards references

Mixed in ref-list

Dedicated std/std-ref elements

Module tree

Sts::NisoSts::*

Sts::IsoSts::*

Despite sharing the same JATS ancestry, the two formats have incompatible content models. Elements with the same XML name (e.g., p, sec, disp-formula) may have different permitted children and attributes. They are implemented as completely separate Ruby class trees.

Library

Usage: NISO STS

The following code parses a NISO STS XML document.

require 'sts'

doc = IO.read('spec/fixtures/tbx-nisosts-0.2.xml')
sts = Sts::NisoSts::Standard.from_xml(doc)
puts sts.to_xml(pretty: true)
# => NISO STS file round-tripped

NISO STS API

# Parse
sts = Sts::NisoSts::Standard.from_xml(xml_string)

# Access elements
sts.front..title_wrap.main
sts.body.sec.first.label

# Serialize back
sts.to_xml
sts.to_xml(pretty: true)

# Check document type
sts.class.name # => "Sts::NisoSts::Standard"

NISO STS root classes

  • Sts::NisoSts::Standard — Book or article root

  • Sts::NisoSts::Front — Front matter (article-meta, journal-meta)

  • Sts::NisoSts::Body — Document body

  • Sts::NisoSts::Back — Back matter (references, footnotes)

Usage: ISOSTS

ISOSTS uses <standard> as the root element and includes MathML 2 for formulae. It adopts TBX (ISO 30042) for terminology sections.

require 'sts'

doc = IO.read('spec/fixtures/iso_sts/feature_doc.xml')
sts = Sts::IsoSts::Standard.from_xml(doc)
puts sts.to_xml(pretty: true)
# => ISOSTS file round-tripped

ISOSTS API

# Parse
sts = Sts::IsoSts::Standard.from_xml(xml_string)

# Access elements
sts.front.iso_meta.title_wrap.main
sts.front.iso_meta.std_ident.doc_number
sts.body.term_sec.first.term_entry.lang_set.first.term

# Serialize back
sts.to_xml
sts.to_xml(pretty: true)

# Check document type
sts.class.name # => "Sts::IsoSts::Standard"

ISOSTS root classes

  • Sts::IsoSts::Standard — Standard document root (<standard>)

  • Sts::IsoSts::Front — Front matter (iso-meta, reg-meta, nat-meta)

  • Sts::IsoSts::Body — Document body (includes term-sec for terminology)

  • Sts::IsoSts::Back — Back matter (annexes, references, footnotes)

ISOSTS MathML 2

ISOSTS uses MathML 2 (not MathML 3 like NISO STS). All MathML is provided by the mml gem, bound per host:

  • IsoSts::* math attributes → Mml::V2::Math

  • TbxIsoTml::* math attributes → Mml::V2::Math (TBX-in-ISOSTS only)

  • NisoSts::* math attributes → Mml::V3::Math

disp_formula = sts.body.sec.first.disp_formula
math = disp_formula.math  # => Mml::V2::Math

# Round-trip preserves mml: prefix
disp_formula.to_xml       # => <disp-formula><mml:math ...>...</mml:math></disp-formula>

MathML 2 and 3 share the same XML namespace (http://www.w3.org/1998/Math/MathML), so Mml::Namespace (the mml gem’s top-level namespace class) is used directly in both IsoSts::Standard#namespace_scope and NisoSts::Standard#namespace_scope.

ISOSTS TBX Terminology

ISOSTS uses TBX (TermBase eXchange, ISO 30042) for terminology sections via term-sec:

# Access terminology entries
term_sec = sts.body.term_sec.first
term_entry = term_sec.term_entry

term_entry.lang_set.each do |lang_set|
  puts lang_set.xml_lang        # => "en"
  puts lang_set.tig.first.term # => "medical device"
end

TBX elements reuse Sts::TbxIsoTml::* classes.

TBX Integration

Both NISO STS and ISOSTS support TBX (TermBase eXchange, ISO 30042) for terminology markup. The TBX elements are in the Sts::TbxIsoTml module:

require 'sts'

# NISO STS with TBX
sts = Sts::NisoSts::Standard.from_xml(xml_with_tbx)

# ISOSTS with TBX
sts = Sts::IsoSts::Standard.from_xml(xml_with_tbx)

Architecture principles

Namespace independence

IsoSts, NisoSts, and TbxIsoTml are independent schemas that genuinely diverge. Each Sts::<Namespace>::<Class> is modelled from its own schema source — never aliased across namespaces, never sharing base classes. The schemas disagree on most elements (e.g., IsoSts::Fig has title/alternatives that NisoSts::Figure lacks), so sharing types would fight the schemas and violate the Open/Closed principle.

Anti-pattern enforcement

spec/anti_patterns_spec.rb runs 9 per-file checks across lib/ to forbid: method_missing, respond_to_missing?, Object.const_get, .send(, instance_variable_set/get, respond_to? type-checks, hand-rolled serialization methods on Serializable subclasses (to_h, to_xml, from_xml, etc.), require_relative, and internal require. See CLAUDE.md for the rationale.

Schema validation

spec/schema_validation_spec.rb validates IsoSts output against the canonical reference-docs/isosts-v1/xsd/ISOSTS.xsd via Nokogiri::XML::Schema. Round-tripping alone cannot prove schema conformance (a model that invents or drops an attribute still round-trips symmetrically); the XSD is the only authoritative check.

Autoload convention

lib/sts.rb autoloads top-level namespaces. Each namespace’s lib/sts/<namespace>.rb autoloads every class in alphabetical order within category groups. External gems (lutaml/model, mml) are eager-required at the top of lib/sts.rb; internal code uses autoload only — no require_relative, no require "sts/…​".

Credits

This gem is developed, maintained and funded by Ribose Inc.

License

The gem is available as open source under the terms of the 2-Clause BSD License.