NewsML-G2 for Ruby, built on lutaml-model.
Parse, manipulate, build and serialize IPTC NewsML-G2 (News Architecture) XML with round-trip fidelity. Targets specification version 2.35, power conformance. The model layer is a port of python-newsmlg2, its full test suite is ported, and the official IPTC specification examples and unit-test suite are adopted as compliance fixtures.
Installation
gem "newsmlg2"
Parsing
require "newsmlg2"
doc = Newsmlg2.parse_file("newsitem.xml") # or Newsmlg2.parse(xml_string)
doc.item # => Newsmlg2::NewsItem (typed)
doc.item..item_class.qcode # => "ninat:text"
doc.item..headlines.first.to_s # => "Fed to halt QE ..."
Every root element dispatches to its typed model: NewsItem, PackageItem, ConceptItem, KnowledgeItem, CatalogItem, PlanningItem or NewsMessage.
QCodes and catalogs
A document carries its own catalog store: inline <catalog> elements plus <catalogRef> hrefs (the IPTC standard catalogs are bundled, so no network access is needed).
doc.catalog_store.get_scheme_for_alias("ninat").uri
# => "http://cv.iptc.org/newscodes/ninature/"
Newsmlg2.qcode_to_uri("ninat:text", doc)
# => "http://cv.iptc.org/newscodes/ninature/text"
Newsmlg2.uri_to_qcode("http://cv.iptc.org/newscodes/ninature/text", doc)
# => "ninat:text"
Building with the DSL
doc = Newsmlg2.build_news_item(guid: "urn:newsml:acme.com:20260830:00001",
lang: "en-GB") do |item|
item. do ||
.item_class qcode: "ninat:text"
.provider qcode: "nprov:acme" do |p|
p.name "Acme News Agency"
end
.version_created "2026-08-30T12:00:00+00:00"
end
item. do |cm|
cm.urgency 2
cm.headline "Eruption of Icelandic volcano"
cm.subject qcode: "medtop:20000962" do |s|
s.name "Volcano"
s.name "Vulkan", xml_lang: "de"
end
end
end
doc.to_xml # => "<?xml version=\"1.0\" ... ?>"
Builder methods are generated from the model metadata: one per attribute (collections accept repeated calls and singular aliases — subject appends to subjects), keyword arguments become child attributes, plain strings wrap into content-bearing types, and blocks nest.
Serialization
doc.to_xml # declaration + canonical 2-space-pretty XML
doc.item..to_xml # any subtree
Serializing an item without a guid raises Newsmlg2::MissingGuidError. The spec’s default attributes (standard, standardversion, conformance, version) are filled in like python-newsmlg2 does.
Architecture
-
lib/newsmlg2/nar_model.rb — the base model: binds the NAR namespace once and provides the declaration DSL (xml_attributes, xml_element, xml_content).
-
lib/newsmlg2/base/ — XSD attribute groups and element groups as mixins (one file per group, ported from python-newsmlg2’s attributegroups.py and the *Group element lists).
-
lib/newsmlg2/types/ — one class per XSD complex type; element names are declared once, at their usage site in the owning model.
-
lib/newsmlg2/items/ — the seven item types, newsMessage, and their structural children (ItemMeta, ContentMeta, PartMeta, GroupSet …).
-
lib/newsmlg2/catalog_store.rb — per-document catalog store and qcode resolution; IPTC catalogs v32–v41 are bundled under lib/newsmlg2/catalogs/.
-
lib/newsmlg2/document.rb — the parse/serialize entry point.
-
lib/newsmlg2/builder.rb — the reflection-driven build DSL.
Compliance
Three test tiers, all green in CI:
-
python-newsmlg2 test suite port — spec/newsmlg2/*_spec.rb.
-
IPTC official examples — all 35 example documents (spec/compliance/examples_spec.rb).
-
IPTC official validation suite — 161 should-pass/should-fail files across all schema versions, ~2100 assertions (spec/compliance/xsd_validation_spec.rb).
IPTC material (examples, schemas, unit-test files) is vendored under spec/fixtures/iptc/ under the IPTC’s CC-BY 4.0 / MIT terms; see spec/fixtures/iptc/README.md.
Development
bundle install
bundle exec rake # full suite
bundle exec rubocop
License
BSD-2-Clause. NewsML-G2 is a trademark of the IPTC; this library is not affiliated with the IPTC.