Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Capture XML namepace prefix and URL within the deserialized data #89

Merged
merged 9 commits into from
Aug 15, 2021
228 changes: 171 additions & 57 deletions spec/converters/xml_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ XML_SCALAR_ARRAY = <<-XML
</items>
XML

XML_SCALAR_ARRAY_WITH_ATTRIBUTE = <<-XML
<?xml version="1.0" encoding="utf-8"?>
<items>
<number>1</number>
<number>2</number>
<number foo="bar">3</number>
</items>
XML

XML_CDATA = <<-XML
<desc><![CDATA[<message>Some Description</message>]]></desc>
XML
Expand Down Expand Up @@ -98,15 +107,6 @@ XML_INLINE_ARRAY_WITHIN_ARRAY = <<-XML
</articles>
XML

XML_NAMESPACE_ARRAY = <<-XML
<?xml version="1.0" encoding="utf-8"?>
<items xmlns:n="http://n">
<n:number>1</n:number>
<n:number>2</n:number>
<number xmlns="http://default">3</number>
</items>
XML

XML_DOCTYPE = <<-XML
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE dblp SYSTEM "dblp.dtd">
Expand Down Expand Up @@ -155,6 +155,24 @@ XML_ALL_EMPTY = <<-XML
</root>
XML

XML_NAMESPACE_ARRAY = <<-XML
<?xml version="1.0" encoding="utf-8"?>
<items xmlns:n="http://n">
<n:number>1</n:number>
<n:number>2</n:number>
<number xmlns="http://default">3</number>
</items>
XML

XML_NAMESPACE_ARRAY_SCALAR_VALUE_PREFIX = <<-XML
<?xml version="1.0" encoding="utf-8"?>
<items xmlns:n="http://n">
<n:number>1</n:number>
<n:number>2</n:number>
<n:number xmlns="http://default">3</n:number>
</items>
XML

XML_NAMESPACE_PREFIXES = <<-XML
<?xml version="1.0" ?>
<root xmlns:a="https://a">
Expand Down Expand Up @@ -320,38 +338,98 @@ describe OQ::Converters::XML do
end

describe "with namespaces" do
it "retains prefixes but strips namespace declarations of a prefixed namespace" do
run_binary(%(<?xml version="1.0"?><a:foo xmlns:a="http://www.w3.org/1999/xhtml">bar</a:foo>), args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"a:foo":"bar"}\n)
describe "without --xmlns" do
it "retains prefixes but strips namespace declarations of a prefixed namespace" do
run_binary(%(<?xml version="1.0"?><a:foo xmlns:a="http://www.w3.org/1999/xhtml">bar</a:foo>), args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"a:foo":"bar"}\n)
end
end
end

it "does not add pefix if none was already present but strips namespace declarations" do
run_binary(%(<?xml version="1.0"?><foo xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:a="http://www.w3.org/1999/xhtml">bar</foo>), args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"foo":"bar"}\n)
it "does not add pefix if none was already present but strips namespace declarations" do
run_binary(%(<?xml version="1.0"?><foo xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:a="http://www.w3.org/1999/xhtml">bar</foo>), args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"foo":"bar"}\n)
end
end
end

it "treats prefixed & unprefixed elements as unique elements" do
run_binary(XML_NESTED_NAMESPACES, args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"root":{"a:foo":"herp","foo":{"bar":{"baz":null}}}}\n)
it "adds namespace attribute properties only to declaring element and handles differentiating prefixed elements" do
run_binary(XML_NESTED_NAMESPACES, args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"root":{"a:foo":"herp","foo":{"bar":{"baz":null}}}}\n)
end
end

it "retains prefixes of scalar value elements" do
run_binary(XML_NAMESPACE_PREFIXES, args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"root":{"foo":"foo","a:bar":"bar"}}\n)
end
end

describe "with --namespace-alias" do
it "should error" do
run_binary(%(<?xml version="1.0"?><a:foo xmlns:a="https://a-namespace">bar</a:foo>), args: ["-i", "xml", "-c", "--namespace-alias", "aa=https://a-namespace", "."], success: false) do |_, _, error|
error.should start_with "oq error:"
end
end
end
end

it "retains prefixes of scalar value elements" do
run_binary(XML_NAMESPACE_PREFIXES, args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"root":{"foo":"foo","a:bar":"bar"}}\n)
describe "with --xmlns" do
it "creates a namespace attribute property" do
run_binary(%(<?xml version="1.0"?><a:foo xmlns:a="http://www.w3.org/1999/xhtml">bar</a:foo>), args: ["-i", "xml", "-c", "--xmlns", "."]) do |output|
output.should eq %({"a:foo":{"@xmlns:a":"http://www.w3.org/1999/xhtml","#text":"bar"}}\n)
end
end

it "does not add pefix if none was already present and creates multiple namespace attribute properties" do
run_binary(%(<?xml version="1.0"?><foo xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:a="http://www.w3.org/1999/xhtml">bar</foo>), args: ["-i", "xml", "-c", "--xmlns", "."]) do |output|
output.should eq %({"foo":{"@xmlns":"urn:oasis:names:tc:SAML:2.0:metadata","@xmlns:a":"http://www.w3.org/1999/xhtml","#text":"bar"}}\n)
end
end

it "treats prefixed & unprefixed elements as unique elements" do
run_binary(XML_NESTED_NAMESPACES, args: ["-i", "xml", "-c", "--xmlns", "."]) do |output|
output.should eq %({"root":{"@xmlns:a":"https://a","@xmlns":"https://b","a:foo":"herp","foo":{"bar":{"@xmlns":"https://c","baz":{"@xmlns":"https://d"}}}}}\n)
end
end

it "retains prefixes of scalar value elements and adds a namespace attribute property" do
run_binary(XML_NAMESPACE_PREFIXES, args: ["-i", "xml", "-c", "--xmlns", "."]) do |output|
output.should eq %({"root":{"@xmlns:a":"https://a","foo":"foo","a:bar":"bar"}}\n)
end
end

describe "with --namespace-alias" do
it "normalizes the provided namespace" do
run_binary(%(<?xml version="1.0"?><a:foo xmlns:a="https://a-namespace">bar</a:foo>), args: ["-i", "xml", "-c", "--xmlns", "--namespace-alias", "aa=https://a-namespace", "."]) do |output|
output.should eq %({"aa:foo":{"@xmlns:aa":"https://a-namespace","#text":"bar"}}\n)
end
end

it "normalizes the default namespace" do
run_binary(%(<?xml version="1.0"?><foo xmlns="https://a-namespace">bar</foo>), args: ["-i", "xml", "-c", "--xmlns", "--namespace-alias", "aa=https://a-namespace", "."]) do |output|
output.should eq %({"aa:foo":{"@xmlns:aa":"https://a-namespace","#text":"bar"}}\n)
end
end

it "normalizes multiple namespaces" do
run_binary(XML_NESTED_NAMESPACES, args: ["-i", "xml", "-c", "--xmlns", "--namespace-alias", "=https://a", "--namespace-alias", "bb=https://b", "."]) do |output|
output.should eq %({"bb:root":{"@xmlns":"https://a","@xmlns:bb":"https://b","foo":"herp","bb:foo":{"bar":{"@xmlns":"https://c","baz":{"@xmlns":"https://d"}}}}}\n)
end
end
end
end
end
end

describe Array do
describe "of scalar values" do
it "should output correctly" do
run_binary(XML_SCALAR_ARRAY, args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"items":{"number":["1","2","3"]}}\n)
end
it "of scalar values" do
run_binary(XML_SCALAR_ARRAY, args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"items":{"number":["1","2","3"]}}\n)
end
end

it "of scalar values with attribute" do
run_binary(XML_SCALAR_ARRAY_WITH_ATTRIBUTE, args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"items":{"number":["1","2",{"@foo":"bar","#text":"3"}]}}\n)
end
end

Expand Down Expand Up @@ -398,9 +476,45 @@ describe OQ::Converters::XML do
end

describe "with namespaces" do
it "treats prefixed & unprefixed elements as unique elements" do
run_binary(XML_NAMESPACE_ARRAY, args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"items":{"n:number":["1","2"],"number":"3"}}\n)
describe "without --xmlns" do
it "treats prefixed & unprefixed elements as unique elements" do
run_binary(XML_NAMESPACE_ARRAY, args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"items":{"n:number":["1","2"],"number":"3"}}\n)
end
end

it "ignores the namespace declaration" do
run_binary(XML_NAMESPACE_ARRAY_SCALAR_VALUE_PREFIX, args: ["-i", "xml", "-c", "."]) do |output|
output.should eq %({"items":{"n:number":["1","2","3"]}}\n)
end
end
end

describe "with --xmlns" do
it "treats prefixed & unprefixed elements as unique elements, adding namespace attribute property as needed" do
run_binary(XML_NAMESPACE_ARRAY, args: ["-i", "xml", "-c", "--xmlns", "."]) do |output|
output.should eq %({"items":{"@xmlns:n":"http://n","n:number":["1","2"],"number":{"@xmlns":"http://default","#text":"3"}}}\n)
end
end

it "expands the scalar value to include a namespace attribute property" do
run_binary(XML_NAMESPACE_ARRAY_SCALAR_VALUE_PREFIX, args: ["-i", "xml", "-c", "--xmlns", "."]) do |output|
output.should eq %({"items":{"@xmlns:n":"http://n","n:number":["1","2",{"@xmlns":"http://default","#text":"3"}]}}\n)
end
end

describe "with --namespace-alias" do
it do
run_binary(XML_NAMESPACE_ARRAY, args: ["-i", "xml", "-c", "--xmlns", "--namespace-alias", "num=http://n", "."]) do |output|
output.should eq %({"items":{"@xmlns:num":"http://n","num:number":["1","2"],"number":{"@xmlns":"http://default","#text":"3"}}}\n)
end
end

it do
run_binary(XML_NAMESPACE_ARRAY, args: ["-i", "xml", "-c", "--xmlns", "--namespace-alias", "=http://n", "--namespace-alias", "d=http://default", "."]) do |output|
output.should eq %({"items":{"@xmlns":"http://n","number":["1","2"],"d:number":{"@xmlns:d":"http://default","#text":"3"}}}\n)
end
end
end
end
end
Expand Down Expand Up @@ -441,66 +555,66 @@ describe OQ::Converters::XML do
end
end
end
end

describe "it allows changing the array item name" do
describe "with a single nesting level" do
it "should emit item tags for non empty values" do
run_binary(%(["x",{}]), args: ["-o", "xml", "--xml-item", "foo", "."]) do |output|
output.should eq(<<-XML
describe "it allows changing the array item name" do
describe "with a single nesting level" do
it "should emit item tags for non empty values" do
run_binary(%(["x",{}]), args: ["-o", "xml", "--xml-item", "foo", "."]) do |output|
output.should eq(<<-XML
<?xml version="1.0" encoding="UTF-8"?>
<root>
<foo>x</foo>
<foo/>
</root>\n
XML
)
end
)
end
end
end

describe "with a larger nesting level" do
it "should emit item tags for non empty values" do
run_binary(%({"a":[[]]}), args: ["-o", "xml", "--xml-item", "foo", "."]) do |output|
output.should eq(<<-XML
describe "with a larger nesting level" do
it "should emit item tags for non empty values" do
run_binary(%({"a":[[]]}), args: ["-o", "xml", "--xml-item", "foo", "."]) do |output|
output.should eq(<<-XML
<?xml version="1.0" encoding="UTF-8"?>
<root>
<a/>
</root>\n
XML
)
end
)
end
end
end
end

describe "it allows changing the indent" do
describe "more spaces" do
it "should emit the extra spaces" do
run_binary(%({"name": "Jim", "age": 12}), args: ["-o", "xml", "--indent", "4", "."]) do |output|
output.should eq(<<-XML
describe "it allows changing the indent" do
describe "more spaces" do
it "should emit the extra spaces" do
run_binary(%({"name": "Jim", "age": 12}), args: ["-o", "xml", "--indent", "4", "."]) do |output|
output.should eq(<<-XML
<?xml version="1.0" encoding="UTF-8"?>
<root>
<name>Jim</name>
<age>12</age>
</root>\n
XML
)
end
)
end
end
end

describe "to tabs" do
it "should emit the indent as tabs" do
run_binary(%({"name": "Jim", "age": 12}), args: ["-o", "xml", "--indent", "3", "--tab", "."]) do |output|
output.should eq(<<-XML
describe "to tabs" do
it "should emit the indent as tabs" do
run_binary(%({"name": "Jim", "age": 12}), args: ["-o", "xml", "--indent", "3", "--tab", "."]) do |output|
output.should eq(<<-XML
<?xml version="1.0" encoding="UTF-8"?>
<root>
\t\t\t<name>Jim</name>
\t\t\t<age>12</age>
</root>\n
XML
)
end
)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions src/converters/json.cr
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Converter for the `OQ::Format::JSON` format.
module OQ::Converters::JSON
def self.deserialize(input : IO, output : IO, **args) : Nil
def self.deserialize(input : IO, output : IO) : Nil
IO.copy input, output
end

def self.serialize(input : IO, output : IO, **args) : Nil
def self.serialize(input : IO, output : IO) : Nil
IO.copy input, output
end
end
9 changes: 9 additions & 0 deletions src/converters/processor_aware.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# :nodoc:
#
# Denotes a converter exposes the related `OQ::Processor`
# instance in order to read configuration options off of it.
module OQ::Converters::ProcessorAware
macro extended
class_property! processor : OQ::Processor
end
end
2 changes: 1 addition & 1 deletion src/converters/simple_yaml.cr
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module OQ::Converters::SimpleYAML
extend self

# ameba:disable Metrics/CyclomaticComplexity
def deserialize(input : IO, output : IO, **args) : Nil
def deserialize(input : IO, output : IO) : Nil
yaml = ::YAML::PullParser.new(input)
json = ::JSON::Builder.new(output)

Expand Down
Loading