Gyoku translates Ruby Hashes to XML.
Gyoku.xml(:find_user => { :id => 123, "v1:Key" => "api" })
# => "<findUser><id>123</id><v1:Key>api</v1:Key></findUser>"
Gyoku is available through Rubygems and can be installed via:
$ gem install gyoku
or add it to your Gemfile like this:
gem 'gyoku', '~> 1.0'
Hash key Symbols are converted to lowerCamelCase Strings.
Gyoku.xml(:lower_camel_case => "key")
# => "<lowerCamelCase>key</lowerCamelCase>"
You can change the default conversion formula to :camelcase
, :upcase
or :none
.
Note that options are passed as a second Hash to the .xml
method.
Gyoku.xml({ :camel_case => "key" }, { :key_converter => :camelcase })
# => "<CamelCase>key</CamelCase>"
Custom key converters. You can use a lambda/Proc to provide customer key converters. This is a great way to leverage active support inflections for domain specific acronyms.
# Use camelize lower which will hook into active support if installed.
Gyoku.xml({ acronym_abc: "value" }, key_converter: lambda { |key| key.camelize(:lower) })
# => "<acronymABC>value</acronymABC>"
Hash key Strings are not converted and may contain namespaces.
Gyoku.xml("XML" => "key")
# => "<XML>key</XML>"
- DateTime objects are converted to xs:dateTime Strings
- Objects responding to :to_datetime (except Strings) are converted to xs:dateTime Strings
- TrueClass and FalseClass objects are converted to "true" and "false" Strings
- NilClass objects are converted to xsi:nil tags
- These conventions are also applied to the return value of objects responding to :call
- All other objects are converted to Strings using :to_s
Gyoku escapes special characters unless the Hash key ends with an exclamation mark.
Gyoku.xml(:escaped => "<tag />", :not_escaped! => "<tag />")
# => "<escaped><tag /></escaped><notEscaped><tag /></notEscaped>"
Hash Keys ending with a forward slash create self-closing tags.
Gyoku.xml(:"self_closing/" => "", "selfClosing/" => nil)
# => "<selfClosing/><selfClosing/>"
In case you need the XML tags to be in a specific order, you can specify the order
through an additional Array stored under the :order!
key.
Gyoku.xml(:name => "Eve", :id => 1, :order! => [:id, :name])
# => "<id>1</id><name>Eve</name>"
Adding XML attributes is rather ugly, but it can be done by specifying an additional
Hash stored under the:attributes!
key.
Gyoku.xml(:person => "Eve", :attributes! => { :person => { :id => 1 } })
# => "<person id=\"1\">Eve</person>"
In addition to using the :attributes!
key, you may also specify attributes through keys beginning with an "@" sign.
Since you'll need to set the attribute within the hash containing the node's contents, a :content!
key can be used
to explicity set the content of the node. The :content!
value may be a String, Hash, or Array.
This is particularly useful for self-closing tags.
Using :attributes!
Gyoku.xml(
"foo/" => "",
:attributes! => {
"foo/" => {
"bar" => "1",
"biz" => "2",
"baz" => "3"
}
}
)
# => "<foo baz=\"3\" bar=\"1\" biz=\"2\"/>"
Using "@" keys and ":content!"
Gyoku.xml(
"foo/" => {
:@bar => "1",
:@biz => "2",
:@baz => "3",
:content! => ""
})
# => "<foo baz=\"3\" bar=\"1\" biz=\"2\"/>"
Example using "@" to get Array of parent tags each with @attributes & :content!
Gyoku.xml(
"foo" => [
{:@name => "bar", :content! => 'gyoku'}
{:@name => "baz", :@some => "attr", :content! => 'rocks!'}
])
# => "<foo name=\"bar\">gyoku</foo><foo name=\"baz\" some=\"attr\">rocks!</foo>"
Unwrapping Arrays. You can specify an optional unwrap
argument to modify the default Array
behavior. unwrap
accepts a boolean flag (false by default) or an Array whitelist of keys to unwrap.
# Default Array behavior
Gyoku.xml({
"foo" => [
{:is => 'great' },
{:is => 'awesome'}
]
})
# => "<foo><is>great</is></foo><foo><is>awesome</is></foo>"
# Unwrap Array behavior
Gyoku.xml({
"foo" => [
{:is => 'great' },
{:is => 'awesome'}
]
}, unwrap: true)
# => "<foo><is>great</is><is>awesome</is></foo>"
# Unwrap Array, whitelist.
# foo is not unwrapped, bar is.
Gyoku.xml({
"foo" => [
{:is => 'great' },
{:is => 'awesome'}
],
"bar" => [
{:is => 'rad' },
{:is => 'cool'}
]
}, unwrap: [:bar])
# => "<foo><is>great</is></foo><foo><is>awesome</is></foo><bar><is>rad</is><is>cool</is></bar>"
Naturally, it would ignore :content! if tag is self-closing:
Gyoku.xml(
"foo/" => [
{:@name => "bar", :content! => 'gyoku'}
{:@name => "baz", :@some => "attr", :content! => 'rocks!'}
])
# => "<foo name=\"bar\"/><foo name=\"baz\" some=\"attr\"/>"
This seems a bit more explicit with the attributes rather than having to maintain a hash of attributes.
For backward compatibility, :attributes!
will still work. However, "@" keys will override :attributes!
keys
if there is a conflict.
Gyoku.xml(:person => {:content! => "Adam", :@id! => 0})
# => "<person id=\"0\">Adam</person>"
Example with ":content!", :attributes! and "@" keys
Gyoku.xml({
:subtitle => {
:@lang => "en",
:content! => "It's Godzilla!"
},
:attributes! => { :subtitle => { "lang" => "jp" } }
}
# => "<subtitle lang=\"en\">It's Godzilla!</subtitle>"
The example above shows an example of how you can use all three at the same time.
Notice that we have the attribute "lang" defined twice.
The @lang
value takes precedence over the :attribute![:subtitle]["lang"]
value.