lutaml-model 0.3.26 → 0.3.27

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1dc709174fab4f4df2214f08b536e0b1aded39f0c9f48a18eb5a4a53da3fc4b6
4
- data.tar.gz: 9eea83160b8210f84d4b2f9baf2ab577ca91d2a737eaf98b175d52385e6fb5d3
3
+ metadata.gz: e00c3fab326d719d8341687a8411797d60ccaf54820380ba7a2dacead6a89792
4
+ data.tar.gz: e46c1dd3d50f6b2bea7da738d94ace488655205deb049170057490f6d1526bf8
5
5
  SHA512:
6
- metadata.gz: 1e75326adeb9b8804f1bcc99104707edc3656e870d16c8af22e07e32ead9f4d78cd87eb372ebb834f2a5d942d58819e0fd3800e23a8099cf951360765223cd25
7
- data.tar.gz: ecc145fb2d9250cf855243c7b9cf468919f2530eed03039bd6c7a521fa534327a1a67c5348237b3d5959e20fa0fc2b2cadc87e57139f451610cd2d7d695f251b
6
+ metadata.gz: ab260d59203839c5fd9b1aa670501c1953c741fe75f0f7ab7261795c54cd19ed6de9807f9b8252c83ce9eee8cf2e6a9116087066e464ca1f35b8b46e29082351
7
+ data.tar.gz: c579a87612ce8e249edcca0c79f0ee2550d40af899e31ee2405ffdd48509e584df449c19bb3489a6871cdf4dfc08c4bc51f482422ea9a7d91f02d706d653cac6
data/README.adoc CHANGED
@@ -1302,6 +1302,69 @@ end
1302
1302
  ====
1303
1303
 
1304
1304
 
1305
+ ==== Encoding Options in XmlAdapter
1306
+
1307
+ XmlAdapter supports the encoding in the following ways:
1308
+
1309
+ . When encoding is not passed in to_xml:
1310
+ ** Default encoding is UTF-8.
1311
+
1312
+ . When encoding is explicitly passed nil:
1313
+ ** Encoding will be nil, show the HexCode(Nokogiri) or ASCII-8bit(Ox).
1314
+
1315
+ . When encoding is passed with some option:
1316
+ ** Encoding option will be selected as passed.
1317
+
1318
+
1319
+ Syntax:
1320
+
1321
+ [source,ruby]
1322
+ ----
1323
+ Example.new(description: " ∑ is my ∏ moniker µ.").to_xml
1324
+ Example.new(description: " ∑ is my ∏ moniker µ.").to_xml(encoding: nil)
1325
+ Example.new(description: " ∑ is my ∏ moniker µ.").to_xml(encoding: "ASCII")
1326
+ ----
1327
+
1328
+ [example]
1329
+ ====
1330
+ The following class will parse the XML snippet below:
1331
+
1332
+ [source,ruby]
1333
+ ----
1334
+ class Example < Lutaml::Model::Serializable
1335
+ attribute :name, :string
1336
+ attribute :description, :string
1337
+ attribute :value, :integer
1338
+
1339
+ xml do
1340
+ root 'example'
1341
+ map_element 'name', to: :name
1342
+ map_content to: :description
1343
+ end
1344
+ end
1345
+ ----
1346
+
1347
+ [source,xml]
1348
+ ----
1349
+ <example><name>John &#x0026; Doe</name> &#x2211; is my &#x220F; moniker &#xB5;.</example>
1350
+ ----
1351
+
1352
+ [source,ruby]
1353
+ ----
1354
+ > Example.from_xml(xml)
1355
+ > #<Example:0x0000000104ac7240 @name="John & Doe", @description=" ∑ is my ∏ moniker µ.">
1356
+ > Example.new(name: "John & Doe", description: " ∑ is my ∏ moniker µ.").to_xml
1357
+ > #<example><name>John &amp; Doe</name> ∑ is my ∏ moniker µ.</example>
1358
+
1359
+ > Example.new(name: "John & Doe", description: " ∑ is my ∏ moniker µ.").to_xml(encoding: nil)
1360
+ > #<example><name>John &amp; Doe</name> &#x2211; is my &#x220F; moniker &#xB5;.</example>
1361
+
1362
+ > Example.new(name: "John & Doe", description: " ∑ is my ∏ moniker µ.").to_xml(encoding: "ASCII")
1363
+ > #<example><name>John &amp; Doe</name> &#8721; is my &#8719; moniker &#181;.</example>
1364
+ ----
1365
+ ====
1366
+
1367
+
1305
1368
  ==== Namespaces
1306
1369
 
1307
1370
  [[root-namespace]]
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Model
5
- VERSION = "0.3.26"
5
+ VERSION = "0.3.27"
6
6
  end
7
7
  end
@@ -13,7 +13,15 @@ module Lutaml
13
13
  end
14
14
 
15
15
  def to_xml(options = {})
16
- builder = Builder::Nokogiri.build(encoding: "UTF-8") do |xml|
16
+ builder_options = {}
17
+
18
+ if options.key?(:encoding)
19
+ builder_options[:encoding] = options[:encoding] unless options[:encoding].nil?
20
+ else
21
+ builder_options[:encoding] = "UTF-8"
22
+ end
23
+
24
+ builder = Builder::Nokogiri.build(builder_options) do |xml|
17
25
  if root.is_a?(Lutaml::Model::XmlAdapter::NokogiriElement)
18
26
  root.build_xml(xml)
19
27
  else
@@ -35,12 +43,11 @@ module Lutaml
35
43
 
36
44
  def prefix_xml(xml, mapping, options)
37
45
  if options.key?(:namespace_prefix)
38
- options[:namespace_prefix] ? xml[options[:namespace_prefix]] : xml
46
+ xml[options[:namespace_prefix]] if options[:namespace_prefix]
39
47
  elsif mapping.namespace_prefix
40
48
  xml[mapping.namespace_prefix]
41
- else
42
- xml
43
49
  end
50
+ xml
44
51
  end
45
52
 
46
53
  def build_ordered_element(xml, element, options = {})
@@ -14,8 +14,15 @@ module Lutaml
14
14
 
15
15
  def to_xml(options = {})
16
16
  builder = Builder::Ox.build
17
- builder.xml.instruct(:xml, encoding: options[:encoding] || "UTF-8", version: options[:version])
17
+ builder_options = { version: options[:version] }
18
18
 
19
+ if options.key?(:encoding)
20
+ builder_options[:encoding] = options[:encoding] unless options[:encoding].nil?
21
+ else
22
+ builder_options[:encoding] = "UTF-8"
23
+ end
24
+
25
+ builder.xml.instruct(:xml, builder_options)
19
26
  if @root.is_a?(Lutaml::Model::XmlAdapter::OxElement)
20
27
  @root.build_xml(builder)
21
28
  elsif ordered?(@root, options)
@@ -66,7 +66,7 @@ module Lutaml
66
66
  options[:tag_name] = rule.name
67
67
 
68
68
  options[:mapper_class] = attribute&.type if attribute
69
- options[:namespace_set] = set_namespace?(rule)
69
+ options[:set_namespace] = set_namespace?(rule)
70
70
 
71
71
  options
72
72
  end
@@ -185,6 +185,7 @@ module Lutaml
185
185
  attributes = options[:xml_attributes] ||= {}
186
186
  attributes = build_attributes(element,
187
187
  xml_mapping, options).merge(attributes)&.compact
188
+
188
189
  if element.respond_to?(:schema_location) && element.schema_location
189
190
  attributes.merge!(element.schema_location.to_xml_attributes)
190
191
  end
@@ -275,7 +276,7 @@ module Lutaml
275
276
  end
276
277
 
277
278
  def set_namespace?(rule)
278
- rule.nil? || !rule.namespace_set? || !rule.namespace.nil?
279
+ rule.nil? || !rule.namespace_set?
279
280
  end
280
281
 
281
282
  def render_element?(rule, element, value)
@@ -336,7 +337,7 @@ module Lutaml
336
337
  end
337
338
 
338
339
  def build_attributes(element, xml_mapping, options = {})
339
- attrs = if options.fetch(:namespace_set, true)
340
+ attrs = if options.fetch(:set_namespace, true)
340
341
  namespace_attributes(xml_mapping)
341
342
  else
342
343
  {}
@@ -148,11 +148,11 @@ RSpec.describe Delegation do
148
148
  end
149
149
 
150
150
  it "provides XML declaration with UTF-8 encoding" \
151
- "if encoding: true option provided" do
151
+ "if encoding: 'UTF-8' option provided" do
152
152
  xml_data = delegation.to_xml(
153
153
  pretty: true,
154
154
  declaration: true,
155
- encoding: true,
155
+ encoding: "UTF-8",
156
156
  )
157
157
  expect(xml_data).to include('<?xml version="1.0" encoding="UTF-8"?>')
158
158
  end
@@ -170,6 +170,15 @@ module MixedContentSpec
170
170
  map_element :value, to: :value
171
171
  end
172
172
  end
173
+
174
+ class HexCode < Lutaml::Model::Serializable
175
+ attribute :content, :string
176
+
177
+ xml do
178
+ root "HexCode"
179
+ map_content to: :content
180
+ end
181
+ end
173
182
  end
174
183
 
175
184
  RSpec.describe "MixedContent" do
@@ -449,7 +458,7 @@ RSpec.describe "MixedContent" do
449
458
 
450
459
  it "serializes special char mixed content correctly" do
451
460
  parsed = MixedContentSpec::SpecialCharContentWithMixedTrue.from_xml(xml)
452
- serialized = parsed.to_xml
461
+ serialized = parsed.to_xml(encoding: "UTF-8")
453
462
 
454
463
  expect(serialized).to include(expected_xml)
455
464
  end
@@ -608,10 +617,68 @@ RSpec.describe "MixedContent" do
608
617
  end
609
618
  end
610
619
  end
620
+
621
+ context "when special char used as full entities, it persist as entities if no encoding provided" do
622
+ let(:xml) do
623
+ <<~XML
624
+ <HexCode>
625
+ &#x2211;computer security&#x220F; type of &#x200B; operation specified &#xB5; by an access right
626
+ </HexCode>
627
+ XML
628
+ end
629
+
630
+ describe ".from_xml" do
631
+ let(:expected_content) { "∑computer security∏ type of ​ operation specified µ by an access right" }
632
+
633
+ it "deserializes special char mixed content correctly" do
634
+ parsed = MixedContentSpec::HexCode.from_xml(xml)
635
+
636
+ expect(parsed.content.strip).to eq(expected_content)
637
+ end
638
+ end
639
+
640
+ describe ".to_xml" do
641
+ context "when default encoding xml" do
642
+ let(:expected_default_encoding_xml) { "∑computer security∏ type of ​ operation specified µ by an access right" }
643
+
644
+ it "serializes special char mixed content correctly with default encoding: UTF-8" do
645
+ parsed = MixedContentSpec::HexCode.from_xml(xml)
646
+ serialized = parsed.to_xml
647
+
648
+ expect(serialized.strip).to include(expected_default_encoding_xml)
649
+ end
650
+ end
651
+
652
+ context "when encoding: nil xml" do
653
+ let(:expected_encoding_nil_nokogiri_xml) { "&#x2211;computer security&#x220F; type of &#x200B; operation specified &#xB5; by an access right" }
654
+ let(:expected_encoding_nil_ox_xml) { "\xE2\x88\x91computer security\xE2\x88\x8F type of \xE2\x80\x8B operation specified \xC2\xB5 by an access right" }
655
+
656
+ it "serializes special char mixed content correctly with encoding: nil to get hexcode" do
657
+ parsed = MixedContentSpec::HexCode.from_xml(xml)
658
+ serialized = parsed.to_xml(encoding: nil)
659
+
660
+ if adapter_class == Lutaml::Model::XmlAdapter::OxAdapter
661
+ expected_output = expected_encoding_nil_ox_xml
662
+ expected_output.force_encoding("ASCII-8BIT")
663
+ else
664
+ expected_output = expected_encoding_nil_nokogiri_xml
665
+ end
666
+
667
+ expect(serialized.strip).to include(expected_output)
668
+ end
669
+ end
670
+ end
671
+ end
611
672
  end
612
673
 
613
674
  describe Lutaml::Model::XmlAdapter::NokogiriAdapter do
614
675
  it_behaves_like "mixed content behavior", described_class
676
+
677
+ it "raises error when serializes special char content with false encoding: 'ABC'" do
678
+ parsed = MixedContentSpec::HexCode.from_xml("<HexCode>&#x2211;computer security</HexCode>")
679
+
680
+ expect { parsed.to_xml(encoding: "ABC") }.to raise_error(StandardError, "unknown encoding name - ABC")
681
+ end
615
682
  end
616
683
 
617
684
  describe Lutaml::Model::XmlAdapter::OxAdapter do
@@ -127,6 +127,17 @@ module XmlMapping
127
127
  end
128
128
  end
129
129
 
130
+ class OverrideDefaultNamespacePrefix < Lutaml::Model::Serializable
131
+ attribute :same_element_name, SameNameDifferentNamespace
132
+
133
+ xml do
134
+ root "OverrideDefaultNamespacePrefix"
135
+ map_element :SameElementName, to: :same_element_name,
136
+ namespace: "http://www.omg.org/spec/XMI/20131001",
137
+ prefix: "abc"
138
+ end
139
+ end
140
+
130
141
  class SchemaLocationOrdered < Lutaml::Model::Serializable
131
142
  attribute :content, :string
132
143
  attribute :second, SchemaLocationOrdered
@@ -220,6 +231,30 @@ module XmlMapping
220
231
  prefix: nil
221
232
  end
222
233
  end
234
+
235
+ class Documentation < Lutaml::Model::Serializable
236
+ attribute :content, :string
237
+
238
+ xml do
239
+ root "documentation", mixed: true
240
+ namespace "http://www.w3.org/2001/XMLSchema", "xsd"
241
+
242
+ map_content to: :content
243
+ end
244
+ end
245
+
246
+ class Schema < Lutaml::Model::Serializable
247
+ attribute :documentation, Documentation, collection: true
248
+
249
+ xml do
250
+ root "schema"
251
+ namespace "http://www.w3.org/2001/XMLSchema", "xsd"
252
+
253
+ map_element :documentation, to: :documentation,
254
+ namespace: "http://www.w3.org/2001/XMLSchema",
255
+ prefix: "xsd"
256
+ end
257
+ end
223
258
  end
224
259
 
225
260
  RSpec.describe Lutaml::Model::XmlMapping do
@@ -245,6 +280,25 @@ RSpec.describe Lutaml::Model::XmlMapping do
245
280
  end
246
281
  end
247
282
 
283
+ context "overriding child namespace prefix" do
284
+ let(:input_xml) do
285
+ <<~XML
286
+ <OverrideDefaultNamespacePrefix xmlns:abc="http://www.omg.org/spec/XMI/20131001" xmlns:GML="http://www.sparxsystems.com/profiles/GML/1.0" xmlns:CityGML="http://www.sparxsystems.com/profiles/CityGML/1.0">
287
+ <abc:SameElementName App="hello">
288
+ <GML:ApplicationSchema>GML App</GML:ApplicationSchema>
289
+ <CityGML:ApplicationSchema>CityGML App</CityGML:ApplicationSchema>
290
+ <abc:ApplicationSchema>App</abc:ApplicationSchema>
291
+ </abc:SameElementName>
292
+ </OverrideDefaultNamespacePrefix>
293
+ XML
294
+ end
295
+
296
+ it "expect to round-trips" do
297
+ parsed = XmlMapping::OverrideDefaultNamespacePrefix.from_xml(input_xml)
298
+ expect(parsed.to_xml).to be_equivalent_to(input_xml)
299
+ end
300
+ end
301
+
248
302
  context "with same name elements" do
249
303
  let(:input_xml) do
250
304
  <<~XML
@@ -859,5 +913,19 @@ RSpec.describe Lutaml::Model::XmlMapping do
859
913
  expect(XmlMapping::SpecialCharContentWithMapAll.from_xml(xml).to_xml).to eq(expected_xml)
860
914
  end
861
915
  end
916
+
917
+ context "when mixed content is true and child is content_mapping" do
918
+ let(:xml) do
919
+ <<~XML
920
+ <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
921
+ <xsd:documentation>asdf</xsd:documentation>
922
+ </xsd:schema>
923
+ XML
924
+ end
925
+
926
+ it "round-trips xml" do
927
+ expect(XmlMapping::Schema.from_xml(xml).to_xml).to be_equivalent_to(xml)
928
+ end
929
+ end
862
930
  end
863
931
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.26
4
+ version: 0.3.27
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-11-12 00:00:00.000000000 Z
11
+ date: 2024-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor