newsmlg2 0.1.1

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.
Files changed (127) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/docs.yml +63 -0
  3. data/.github/workflows/links.yml +99 -0
  4. data/.github/workflows/performance.yml +25 -0
  5. data/.github/workflows/rake.yml +19 -0
  6. data/.github/workflows/release.yml +34 -0
  7. data/.gitignore +17 -0
  8. data/.rubocop.yml +51 -0
  9. data/CHANGELOG.md +31 -0
  10. data/CLAUDE.md +77 -0
  11. data/Gemfile +15 -0
  12. data/LICENSE +24 -0
  13. data/README.adoc +135 -0
  14. data/Rakefile +15 -0
  15. data/docs/Gemfile +6 -0
  16. data/docs/_config.yml +4 -0
  17. data/docs/index.md +15 -0
  18. data/docs/lychee.toml +4 -0
  19. data/docs/usage.md +36 -0
  20. data/lib/newsmlg2/base/administrative_metadata_group.rb +40 -0
  21. data/lib/newsmlg2/base/arbitrary_value_attributes.rb +13 -0
  22. data/lib/newsmlg2/base/authority_attributes.rb +14 -0
  23. data/lib/newsmlg2/base/common_power_attributes.rb +17 -0
  24. data/lib/newsmlg2/base/concept_definition_group.rb +25 -0
  25. data/lib/newsmlg2/base/concept_relationships_group.rb +22 -0
  26. data/lib/newsmlg2/base/confirmation_status_attributes.rb +13 -0
  27. data/lib/newsmlg2/base/deprecated_link_attributes.rb +14 -0
  28. data/lib/newsmlg2/base/descriptive_metadata_group.rb +54 -0
  29. data/lib/newsmlg2/base/entity_details_group.rb +28 -0
  30. data/lib/newsmlg2/base/flex_attributes.rb +13 -0
  31. data/lib/newsmlg2/base/i18n_attributes.rb +14 -0
  32. data/lib/newsmlg2/base/item_management_group.rb +59 -0
  33. data/lib/newsmlg2/base/media_content_characteristics1.rb +22 -0
  34. data/lib/newsmlg2/base/news_content_attributes.rb +18 -0
  35. data/lib/newsmlg2/base/news_content_characteristics.rb +30 -0
  36. data/lib/newsmlg2/base/news_content_type_attributes.rb +17 -0
  37. data/lib/newsmlg2/base/persistent_edit_attributes.rb +13 -0
  38. data/lib/newsmlg2/base/qualifying_attributes.rb +13 -0
  39. data/lib/newsmlg2/base/quantify_attributes.rb +13 -0
  40. data/lib/newsmlg2/base/ranking_attributes.rb +13 -0
  41. data/lib/newsmlg2/base/recurrence_rule_attributes.rb +18 -0
  42. data/lib/newsmlg2/base/target_resource_attributes.rb +20 -0
  43. data/lib/newsmlg2/base/time_validity_attributes.rb +13 -0
  44. data/lib/newsmlg2/base.rb +35 -0
  45. data/lib/newsmlg2/builder/node.rb +125 -0
  46. data/lib/newsmlg2/builder.rb +69 -0
  47. data/lib/newsmlg2/catalog.rb +38 -0
  48. data/lib/newsmlg2/catalog_cache.rb +49 -0
  49. data/lib/newsmlg2/catalog_ref.rb +13 -0
  50. data/lib/newsmlg2/catalog_store.rb +66 -0
  51. data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_32.xml +620 -0
  52. data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_33.xml +625 -0
  53. data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_34.xml +626 -0
  54. data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_35.xml +635 -0
  55. data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_36.xml +644 -0
  56. data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_37.xml +661 -0
  57. data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_38.xml +674 -0
  58. data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_39.xml +682 -0
  59. data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_40.xml +724 -0
  60. data/lib/newsmlg2/catalogs/catalog.IPTC-G2-Standards_41.xml +729 -0
  61. data/lib/newsmlg2/configuration.rb +61 -0
  62. data/lib/newsmlg2/document.rb +123 -0
  63. data/lib/newsmlg2/errors.rb +18 -0
  64. data/lib/newsmlg2/i18n.rb +20 -0
  65. data/lib/newsmlg2/items/any_item.rb +180 -0
  66. data/lib/newsmlg2/items/catalog_item.rb +24 -0
  67. data/lib/newsmlg2/items/concept_item.rb +23 -0
  68. data/lib/newsmlg2/items/content_meta.rb +73 -0
  69. data/lib/newsmlg2/items/item_ref.rb +13 -0
  70. data/lib/newsmlg2/items/knowledge_item.rb +68 -0
  71. data/lib/newsmlg2/items/news_item.rb +130 -0
  72. data/lib/newsmlg2/items/news_message.rb +142 -0
  73. data/lib/newsmlg2/items/package_item.rb +82 -0
  74. data/lib/newsmlg2/items/part_meta.rb +68 -0
  75. data/lib/newsmlg2/items/planning_item.rb +160 -0
  76. data/lib/newsmlg2/nar_model.rb +76 -0
  77. data/lib/newsmlg2/nar_namespace.rb +10 -0
  78. data/lib/newsmlg2/nitf_namespace.rb +9 -0
  79. data/lib/newsmlg2/same_as_scheme.rb +15 -0
  80. data/lib/newsmlg2/scheme.rb +30 -0
  81. data/lib/newsmlg2/types/approximate_date_time_prop_type.rb +14 -0
  82. data/lib/newsmlg2/types/bag.rb +16 -0
  83. data/lib/newsmlg2/types/block_types.rb +62 -0
  84. data/lib/newsmlg2/types/concept.rb +36 -0
  85. data/lib/newsmlg2/types/concept_id.rb +17 -0
  86. data/lib/newsmlg2/types/concept_name_type.rb +17 -0
  87. data/lib/newsmlg2/types/content_meta_types.rb +152 -0
  88. data/lib/newsmlg2/types/date_opt_time_prop_type.rb +12 -0
  89. data/lib/newsmlg2/types/date_time_or_null_prop_type.rb +12 -0
  90. data/lib/newsmlg2/types/date_time_prop_type.rb +12 -0
  91. data/lib/newsmlg2/types/event_details.rb +213 -0
  92. data/lib/newsmlg2/types/ext_property.rb +21 -0
  93. data/lib/newsmlg2/types/facet.rb +17 -0
  94. data/lib/newsmlg2/types/flex1_prop_type.rb +32 -0
  95. data/lib/newsmlg2/types/flex_location_prop_type.rb +43 -0
  96. data/lib/newsmlg2/types/flex_party_prop_type.rb +49 -0
  97. data/lib/newsmlg2/types/flex_prop2_type.rb +26 -0
  98. data/lib/newsmlg2/types/flex_prop_type.rb +17 -0
  99. data/lib/newsmlg2/types/geo.rb +92 -0
  100. data/lib/newsmlg2/types/hierarchy_info.rb +17 -0
  101. data/lib/newsmlg2/types/ids.rb +28 -0
  102. data/lib/newsmlg2/types/inline_types.rb +56 -0
  103. data/lib/newsmlg2/types/intl_string_type.rb +17 -0
  104. data/lib/newsmlg2/types/intl_string_type2.rb +14 -0
  105. data/lib/newsmlg2/types/item_management.rb +74 -0
  106. data/lib/newsmlg2/types/link.rb +40 -0
  107. data/lib/newsmlg2/types/object_details.rb +40 -0
  108. data/lib/newsmlg2/types/party_details.rb +258 -0
  109. data/lib/newsmlg2/types/poi.rb +79 -0
  110. data/lib/newsmlg2/types/qcode_prop_type.rb +12 -0
  111. data/lib/newsmlg2/types/qual_prop_type.rb +23 -0
  112. data/lib/newsmlg2/types/qual_rel_prop_type.rb +18 -0
  113. data/lib/newsmlg2/types/related_concept.rb +71 -0
  114. data/lib/newsmlg2/types/rights.rb +84 -0
  115. data/lib/newsmlg2/types/ruby_annotation.rb +55 -0
  116. data/lib/newsmlg2/types/same_as.rb +17 -0
  117. data/lib/newsmlg2/types/truncated_date_time_prop_type.rb +13 -0
  118. data/lib/newsmlg2/types/versioned_string_type.rb +10 -0
  119. data/lib/newsmlg2/types/xml_base.rb +12 -0
  120. data/lib/newsmlg2/types/xml_lang.rb +12 -0
  121. data/lib/newsmlg2/types.rb +166 -0
  122. data/lib/newsmlg2/utils.rb +42 -0
  123. data/lib/newsmlg2/version.rb +5 -0
  124. data/lib/newsmlg2.rb +181 -0
  125. data/lib/tasks/performance.rake +72 -0
  126. data/newsmlg2.gemspec +34 -0
  127. metadata +185 -0
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Newsmlg2
4
+ # Registry of the NewsML-G2 root models in a lutaml-model global context,
5
+ # keyed by element id. This is the single source of truth for
6
+ # element-name → class resolution (root dispatch, itemSet items) —
7
+ # following the plurimath/mml pattern, library code never compares
8
+ # element-name strings itself.
9
+ module Configuration
10
+ CONTEXT_ID = :newsmlg2
11
+
12
+ class << self
13
+ def context
14
+ Lutaml::Model::GlobalContext.context(CONTEXT_ID)
15
+ end
16
+
17
+ # Rebuilds the built-in context from the registered models.
18
+ def populate_context!
19
+ Lutaml::Model::GlobalContext.unregister_context(CONTEXT_ID) if context
20
+ type_context = Lutaml::Model::GlobalContext.create_context(
21
+ id: CONTEXT_ID,
22
+ registry: Lutaml::Model::TypeRegistry.new,
23
+ fallback_to: [:default]
24
+ )
25
+ register_models_in(type_context)
26
+ Lutaml::Model::GlobalContext.clear_caches
27
+ type_context
28
+ end
29
+
30
+ # Registers a model under its element id (see the registration block
31
+ # at the bottom of lib/newsmlg2.rb).
32
+ def register_model(klass, id:)
33
+ normalized_id = id.to_sym
34
+ registered_models[normalized_id] = klass
35
+ (context || populate_context!).registry.register(normalized_id, klass)
36
+ klass
37
+ end
38
+
39
+ # Resolves an element name to its registered model class, or nil for
40
+ # unregistered names (non-element nodes, foreign roots).
41
+ def resolve(element_name)
42
+ name = element_name.to_sym
43
+ return nil unless Lutaml::Model::GlobalContext.resolvable?(name, CONTEXT_ID)
44
+
45
+ Lutaml::Model::GlobalContext.resolve_type(name, CONTEXT_ID)
46
+ end
47
+
48
+ private
49
+
50
+ def register_models_in(type_context)
51
+ registered_models.each do |model_id, klass|
52
+ type_context.registry.register(model_id, klass)
53
+ end
54
+ end
55
+
56
+ def registered_models
57
+ @registered_models ||= {}
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Newsmlg2
4
+ # The NewsML-G2 document entry point: parses XML into a typed item (or
5
+ # newsMessage), exposes it, and serializes back to XML. Each document owns
6
+ # its CatalogStore, built from inline catalogs and catalogRefs.
7
+ #
8
+ # doc = Newsmlg2.parse(xml) # or Newsmlg2.parse_file(path)
9
+ # doc.item # => Newsmlg2::NewsItem
10
+ # doc.item.content_meta.headlines.first
11
+ # doc.catalog_store.get_scheme_for_alias("ninat")
12
+ # doc.to_xml # => declaration + item XML
13
+ #
14
+ # Root dispatch and itemSet resolution go through the Configuration
15
+ # registry; all model parsing is lutaml-model's from_xml. The gem never
16
+ # references a specific XML parser — the adapter is the consumer's
17
+ # choice via Lutaml::Model::Config.
18
+ class Document
19
+ class << self
20
+ # Parses NewsML-G2 XML into a Document.
21
+ def parse(xml)
22
+ with_resolved_adapter do
23
+ root_name, klass = root_class(xml)
24
+ unless klass
25
+ raise UnknownRootElement,
26
+ "'#{root_name}' is not a NewsML-G2 item or newsMessage root element"
27
+ end
28
+
29
+ new(klass.from_xml(xml))
30
+ end
31
+ end
32
+
33
+ # Parses a NewsML-G2 XML file into a Document.
34
+ def parse_file(path)
35
+ parse(File.read(path))
36
+ end
37
+
38
+ private
39
+
40
+ # Runs the block with the consumer's configured XML adapter; if none
41
+ # resolves (fresh install, unconfigured default), falls back to the
42
+ # REXML adapter, which ships with Ruby — the gem never depends on a
43
+ # specific parser.
44
+ def with_resolved_adapter(&)
45
+ Lutaml::Model::Config.adapter_for(:xml)
46
+ yield
47
+ rescue Lutaml::Model::UnknownAdapterTypeError, LoadError
48
+ Lutaml::Model::Config.with_adapter(xml: :rexml, &)
49
+ end
50
+
51
+ # NewsML-G2 has eight possible root elements and lutaml-model has no
52
+ # multi-root dispatch, so the document's root element name is read
53
+ # once through the configured adapter and resolved to its registered
54
+ # model class. No element-name strings live in this file — the
55
+ # registry (lib/newsmlg2.rb registration block) is the single source
56
+ # of truth.
57
+ def root_class(xml)
58
+ root = Lutaml::Model::Config.adapter_for(:xml).parse(xml).root
59
+ name = root.name.sub(/\A[\w.-]+:/, '')
60
+ [name, Configuration.resolve(name)]
61
+ rescue StandardError
62
+ ['', nil]
63
+ end
64
+ end
65
+
66
+ attr_reader :item
67
+
68
+ # @param item [Newsmlg2::AnyItem, Newsmlg2::NewsMessage]
69
+ def initialize(item = nil)
70
+ @item = item
71
+ @catalog_store = CatalogStore.new
72
+ load_catalogs
73
+ end
74
+
75
+ # Replaces the document's item and rebuilds its catalog store.
76
+ def item=(new_item)
77
+ unless new_item.is_a?(AnyItem) || new_item.is_a?(NewsMessage)
78
+ raise ArgumentError,
79
+ "expected a Newsmlg2 item or NewsMessage, got #{new_item.class}"
80
+ end
81
+
82
+ @item = new_item
83
+ @catalog_store = CatalogStore.new
84
+ load_catalogs
85
+ end
86
+
87
+ # The catalogs known to this document (inline catalogs plus catalogRefs
88
+ # resolvable through the bundled IPTC catalog cache).
89
+ def catalog_store
90
+ @catalog_store ||= CatalogStore.new.tap { |store| load_catalogs_into(store) }
91
+ end
92
+
93
+ # Serializes the document: XML declaration plus the item, validating that
94
+ # a guid is present (items only).
95
+ def to_xml(**options)
96
+ item.validate! if item.is_a?(AnyItem)
97
+ item.to_xml({ declaration: true }.merge(options))
98
+ end
99
+ alias to_xml_string to_xml
100
+
101
+ private
102
+
103
+ def load_catalogs
104
+ load_catalogs_into(catalog_store)
105
+ end
106
+
107
+ def load_catalogs_into(store)
108
+ return unless item
109
+
110
+ case item
111
+ when AnyItem then load_catalog_holders(store, item)
112
+ when NewsMessage then load_catalog_holders(store, item.header)
113
+ end
114
+ end
115
+
116
+ def load_catalog_holders(store, holder)
117
+ return unless holder
118
+
119
+ holder.catalogs.to_a.each { |catalog| store.add_catalog(catalog) }
120
+ holder.catalog_refs.to_a.each { |ref| store.add_catalog_ref(ref.href) }
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Newsmlg2
4
+ class Error < StandardError; end
5
+
6
+ # No catalog known to the document declares this scheme alias.
7
+ class AliasNotFoundInCatalogs < Error; end
8
+
9
+ # No catalog known to the document declares this scheme URI.
10
+ class UriNotFoundInCatalogs < Error; end
11
+ URINotFoundInCatalogs = UriNotFoundInCatalogs
12
+
13
+ # The parsed root element is not a NewsML-G2 item or newsMessage.
14
+ class UnknownRootElement < Error; end
15
+
16
+ # An item without a guid cannot be serialized.
17
+ class MissingGuidError < Error; end
18
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Newsmlg2
4
+ # Helpers for multi-language content collections (elements carrying
5
+ # xml:lang, such as ConceptNameType values).
6
+ module I18n
7
+ module_function
8
+
9
+ # The languages used by a collection of localized elements.
10
+ def languages(collection)
11
+ collection.filter_map(&:xml_lang).uniq
12
+ end
13
+
14
+ # The first element of the collection matching the given language tag
15
+ # (exact match), or nil.
16
+ def for_language(collection, lang)
17
+ collection.find { |item| item.xml_lang == lang }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Newsmlg2
4
+ # An action which is executed at this hop in the hop history.
5
+ class Action < Newsmlg2::Types::QualRelPropType
6
+ xml_attributes :target, :targeturi, :timestamp
7
+
8
+ xml do
9
+ element 'action'
10
+ end
11
+ end
12
+
13
+ # A single hop of the Hop History.
14
+ class Hop < Newsmlg2::NarModel
15
+ include Newsmlg2::Base::CommonPowerAttributes
16
+
17
+ xml_attributes :seq, :timestamp
18
+
19
+ xml_element :parties, xml: 'party',
20
+ type: Newsmlg2::Types::Party, collection: true
21
+ xml_element :actions, xml: 'action',
22
+ type: Newsmlg2::Action, collection: true
23
+
24
+ xml do
25
+ element 'hop'
26
+ end
27
+ end
28
+
29
+ # A history of the creation and modifications of the content object of
30
+ # this item, expressed as a sequence of hops.
31
+ class HopHistory < Newsmlg2::NarModel
32
+ xml_element :hops, xml: 'hop', type: Newsmlg2::Hop, collection: true
33
+
34
+ xml do
35
+ element 'hopHistory'
36
+ end
37
+ end
38
+
39
+ # Time stamp representing an optionally truncated date and time.
40
+ class Timestamp < Newsmlg2::Types::TruncatedDateTimePropType
41
+ xml do
42
+ element 'timestamp'
43
+ end
44
+ end
45
+
46
+ # A step in the pubHistory.
47
+ class Published < Newsmlg2::NarModel
48
+ include Newsmlg2::Base::CommonPowerAttributes
49
+
50
+ xml_attributes :qcode, :uri, :literal
51
+
52
+ xml_element :timestamp, xml: 'timestamp',
53
+ type: Newsmlg2::Timestamp
54
+ xml_element :names, xml: 'name',
55
+ type: Newsmlg2::Types::ConceptNameType, collection: true
56
+ xml_element :related, xml: 'related',
57
+ type: Newsmlg2::Types::Related, collection: true
58
+ xml_element :published_ext_properties, xml: 'publishedExtProperty',
59
+ type: Newsmlg2::Types::Flex2ExtPropType, collection: true
60
+
61
+ xml do
62
+ element 'published'
63
+ end
64
+ end
65
+
66
+ # One to many datasets about publishing this item.
67
+ class PubHistory < Newsmlg2::NarModel
68
+ xml_element :published, xml: 'published',
69
+ type: Newsmlg2::Published, collection: true
70
+
71
+ xml do
72
+ element 'pubHistory'
73
+ end
74
+ end
75
+
76
+ # An assertion about a concept. XSD AssertType carries xs:any ##any
77
+ # content — NAR-namespace properties (name, geoAreaDetails, …) or
78
+ # provider extensions — preserved verbatim in #content.
79
+ class Assert < Newsmlg2::NarModel
80
+ include Newsmlg2::Base::CommonPowerAttributes
81
+ include Newsmlg2::Base::I18NAttributes
82
+
83
+ xml_attributes :qcode, :uri, :literal
84
+
85
+ attribute :content, :string
86
+
87
+ xml do
88
+ element 'assert'
89
+ map_all to: :content
90
+ end
91
+ end
92
+
93
+ # Inline reference: the concept represented by the content identified by
94
+ # the local identifier(s).
95
+ class InlineRef < Newsmlg2::Types::Flex1PropType
96
+ include Newsmlg2::Base::QuantifyAttributes
97
+
98
+ xml_attributes :idrefs
99
+
100
+ xml do
101
+ element 'inlineRef'
102
+ end
103
+ end
104
+
105
+ # Refers to the ids of elements whose values have been derived from the
106
+ # concept represented by this property.
107
+ class DerivedFrom < Newsmlg2::Types::Flex1PropType
108
+ xml_attributes :idrefs
109
+
110
+ xml do
111
+ element 'derivedFrom'
112
+ end
113
+ end
114
+
115
+ # Represents the non-Concept value that was used for deriving the value of
116
+ # one or more properties in this NewsML-G2 item.
117
+ class DerivedFromValue < Newsmlg2::NarModel
118
+ include Newsmlg2::Base::CommonPowerAttributes
119
+
120
+ xml_attributes :sourceidref, :idrefs
121
+
122
+ xml do
123
+ element 'derivedFromValue'
124
+ end
125
+ end
126
+
127
+ # A set of properties directly associated with the Item.
128
+ class ItemMeta < Newsmlg2::NarModel
129
+ include Newsmlg2::Base::CommonPowerAttributes
130
+ include Newsmlg2::Base::I18NAttributes
131
+ include Newsmlg2::Base::ItemManagementGroup
132
+
133
+ xml_element :links, xml: 'link',
134
+ type: Newsmlg2::Types::Link, collection: true
135
+ xml_element :item_meta_ext_properties, xml: 'itemMetaExtProperty',
136
+ type: Newsmlg2::Types::Flex2ExtPropType, collection: true
137
+
138
+ xml do
139
+ element 'itemMeta'
140
+ end
141
+ end
142
+
143
+ # Abstract base of all G2 items. Item subclasses declare their own element
144
+ # name ("newsItem", "packageItem", …) and content model.
145
+ class AnyItem < Newsmlg2::NarModel
146
+ include Newsmlg2::Base::I18NAttributes
147
+
148
+ attribute :standard, :string, default: -> { 'NewsML-G2' }
149
+ attribute :standardversion, :string, default: -> { Newsmlg2::SPEC_VERSION }
150
+ attribute :conformance, :string, default: -> { 'power' }
151
+ attribute :guid, :string
152
+ attribute :version, :string, default: -> { '1' }
153
+
154
+ xml do
155
+ map_attribute 'standard', to: :standard, render_default: true
156
+ map_attribute 'standardversion', to: :standardversion, render_default: true
157
+ map_attribute 'conformance', to: :conformance, render_default: true
158
+ map_attribute 'guid', to: :guid
159
+ map_attribute 'version', to: :version, render_default: true
160
+ end
161
+
162
+ xml_element :catalog_refs, xml: 'catalogRef',
163
+ type: Newsmlg2::CatalogRef, collection: true
164
+ xml_element :catalogs, xml: 'catalog',
165
+ type: Newsmlg2::Catalog, collection: true
166
+ xml_element :hop_history, xml: 'hopHistory', type: Newsmlg2::HopHistory
167
+ xml_element :pub_history, xml: 'pubHistory', type: Newsmlg2::PubHistory
168
+ xml_element :rights_infos, xml: 'rightsInfo',
169
+ type: Newsmlg2::Types::RightsInfo, collection: true
170
+ xml_element :item_meta, xml: 'itemMeta', type: Newsmlg2::ItemMeta
171
+
172
+ # Raises unless the item carries the attributes any NewsML-G2 item
173
+ # requires before serialization.
174
+ def validate!
175
+ raise MissingGuidError, "#{self.class.name.split('::').last} needs a guid" if guid.to_s.empty?
176
+
177
+ self
178
+ end
179
+ end
180
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Newsmlg2
4
+ # The container of a single catalog.
5
+ class CatalogContainer < Newsmlg2::NarModel
6
+ xml_element :catalog, xml: 'catalog', type: Newsmlg2::Catalog
7
+
8
+ xml do
9
+ element 'catalogContainer'
10
+ end
11
+ end
12
+
13
+ # An Item containing a single managed NewsML-G2 catalog.
14
+ class CatalogItem < AnyItem
15
+ xml_element :content_meta, xml: 'contentMeta',
16
+ type: Newsmlg2::ContentMetaCat
17
+ xml_element :catalog_container, xml: 'catalogContainer',
18
+ type: Newsmlg2::CatalogContainer
19
+
20
+ xml do
21
+ element 'catalogItem'
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Newsmlg2
4
+ # An Item containing information about a concept.
5
+ class ConceptItem < AnyItem
6
+ xml_element :content_meta, xml: 'contentMeta',
7
+ type: Newsmlg2::ContentMetaAcD
8
+ xml_element :asserts, xml: 'assert',
9
+ type: Newsmlg2::Assert, collection: true
10
+ xml_element :inline_refs, xml: 'inlineRef',
11
+ type: Newsmlg2::InlineRef, collection: true
12
+ xml_element :derived_from, xml: 'derivedFrom',
13
+ type: Newsmlg2::DerivedFrom, collection: true
14
+ xml_element :derived_from_values, xml: 'derivedFromValue',
15
+ type: Newsmlg2::DerivedFromValue, collection: true
16
+ xml_element :concept, xml: 'concept',
17
+ type: Newsmlg2::Types::Concept
18
+
19
+ xml do
20
+ element 'conceptItem'
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Newsmlg2
4
+ # The full content metadata type (administrative + full descriptive
5
+ # properties) used by news and package items; element name "contentMeta"
6
+ # is declared by the owning item.
7
+ class ContentMeta < Newsmlg2::NarModel
8
+ include Newsmlg2::Base::CommonPowerAttributes
9
+ include Newsmlg2::Base::I18NAttributes
10
+
11
+ # python-newsmlg2 fixtures carry an in-namespace <name> inside
12
+ # contentMeta (an xs:any-style provider extension in those files);
13
+ # modelled so the value round-trips instead of being hoisted.
14
+ xml_element :names, xml: 'name',
15
+ type: Newsmlg2::Types::ConceptNameType, collection: true
16
+ xml_element :icons, xml: 'icon',
17
+ type: Newsmlg2::Types::Icon, collection: true
18
+ include Newsmlg2::Base::AdministrativeMetadataGroup
19
+ include Newsmlg2::Base::DescriptiveMetadataGroup
20
+
21
+ xml_element :content_meta_ext_properties, xml: 'contentMetaExtProperty',
22
+ type: Newsmlg2::Types::Flex2ExtPropType, collection: true
23
+
24
+ xml do
25
+ element 'contentMeta'
26
+ end
27
+ end
28
+
29
+ # Content metadata with the core descriptive set, used by concept,
30
+ # knowledge and planning items.
31
+ class ContentMetaAcD < Newsmlg2::NarModel
32
+ include Newsmlg2::Base::CommonPowerAttributes
33
+ include Newsmlg2::Base::I18NAttributes
34
+
35
+ # python-newsmlg2 fixtures carry an in-namespace <name> inside
36
+ # contentMeta (an xs:any-style provider extension in those files);
37
+ # modelled so the value round-trips instead of being hoisted.
38
+ xml_element :names, xml: 'name',
39
+ type: Newsmlg2::Types::ConceptNameType, collection: true
40
+ xml_element :icons, xml: 'icon',
41
+ type: Newsmlg2::Types::Icon, collection: true
42
+ include Newsmlg2::Base::AdministrativeMetadataGroup
43
+ include Newsmlg2::Base::DescriptiveMetadataCoreGroup
44
+
45
+ xml_element :content_meta_ext_properties, xml: 'contentMetaExtProperty',
46
+ type: Newsmlg2::Types::Flex2ExtPropType, collection: true
47
+
48
+ xml do
49
+ element 'contentMeta'
50
+ end
51
+ end
52
+
53
+ # The restricted content metadata of a catalog item.
54
+ class ContentMetaCat < Newsmlg2::NarModel
55
+ include Newsmlg2::Base::CommonPowerAttributes
56
+ include Newsmlg2::Base::I18NAttributes
57
+
58
+ xml_element :content_created, xml: 'contentCreated',
59
+ type: Newsmlg2::Types::TruncatedDateTimePropType
60
+ xml_element :content_modified, xml: 'contentModified',
61
+ type: Newsmlg2::Types::TruncatedDateTimePropType
62
+ xml_element :creators, xml: 'creator',
63
+ type: Newsmlg2::Types::FlexAuthorPropType, collection: true
64
+ xml_element :contributors, xml: 'contributor',
65
+ type: Newsmlg2::Types::FlexAuthorPropType, collection: true
66
+ xml_element :alt_ids, xml: 'altId',
67
+ type: Newsmlg2::Types::AltId, collection: true
68
+
69
+ xml do
70
+ element 'contentMeta'
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Newsmlg2
4
+ # A reference to a target item or Web resource. Official IPTC examples
5
+ # carry media characteristics (width, height, …) on itemRef.
6
+ class ItemRef < Newsmlg2::Types::Link1Type
7
+ include Newsmlg2::Base::NewsContentCharacteristics
8
+
9
+ xml do
10
+ element 'itemRef'
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Newsmlg2
4
+ # An unordered set of concepts.
5
+ class ConceptSet < Newsmlg2::NarModel
6
+ include Newsmlg2::Base::CommonPowerAttributes
7
+
8
+ xml_element :concepts, xml: 'concept',
9
+ type: Newsmlg2::Types::Concept, collection: true
10
+
11
+ xml do
12
+ element 'conceptSet'
13
+ end
14
+ end
15
+
16
+ # Metadata about a scheme conveyed by a Knowledge Item.
17
+ class SchemeMeta < Newsmlg2::NarModel
18
+ include Newsmlg2::Base::CommonPowerAttributes
19
+ include Newsmlg2::Base::AuthorityAttributes
20
+
21
+ xml_element :same_as_schemes, xml: 'sameAsScheme',
22
+ type: Newsmlg2::SameAsScheme, collection: true
23
+ xml_element :names, xml: 'name',
24
+ type: Newsmlg2::Types::ConceptNameType, collection: true
25
+ xml_element :definitions, xml: 'definition',
26
+ type: Newsmlg2::Types::Definition, collection: true
27
+ xml_element :notes, xml: 'note',
28
+ type: Newsmlg2::Types::Note, collection: true
29
+ xml_element :related, xml: 'related',
30
+ type: Newsmlg2::Types::Related, collection: true
31
+ xml_element :scheme_meta_ext_properties, xml: 'schemeMetaExtProperty',
32
+ type: Newsmlg2::Types::Flex2ExtPropType, collection: true
33
+
34
+ xml_attributes(
35
+ :uri, :preferredalias, :concepttype,
36
+ :schemecreated, :schememodified, :schemeretired
37
+ )
38
+
39
+ xml do
40
+ element 'schemeMeta'
41
+ end
42
+ end
43
+
44
+ # An Item used for collating a set of concept definitions to form the
45
+ # physical representation of a controlled vocabulary.
46
+ class KnowledgeItem < AnyItem
47
+ xml_element :content_meta, xml: 'contentMeta',
48
+ type: Newsmlg2::ContentMetaAcD
49
+ xml_element :part_metas, xml: 'partMeta',
50
+ type: Newsmlg2::PartMeta, collection: true
51
+ xml_element :asserts, xml: 'assert',
52
+ type: Newsmlg2::Assert, collection: true
53
+ xml_element :inline_refs, xml: 'inlineRef',
54
+ type: Newsmlg2::InlineRef, collection: true
55
+ xml_element :derived_from, xml: 'derivedFrom',
56
+ type: Newsmlg2::DerivedFrom, collection: true
57
+ xml_element :derived_from_values, xml: 'derivedFromValue',
58
+ type: Newsmlg2::DerivedFromValue, collection: true
59
+ xml_element :concept_set, xml: 'conceptSet',
60
+ type: Newsmlg2::ConceptSet
61
+ xml_element :scheme_meta, xml: 'schemeMeta',
62
+ type: Newsmlg2::SchemeMeta
63
+
64
+ xml do
65
+ element 'knowledgeItem'
66
+ end
67
+ end
68
+ end