FastXML
Fast Ruby Hash to XML and XML to Ruby Hash converter written in pure C.
Installation
Add this line to your application's Gemfile:
gem 'fast-xml'
And then execute:
$ bundle
Or install it yourself as:
$ gem install fast-xml
Release Notes
See CHANGELOG.md
Usage
Convert hash toXML
require 'fastxml'
FastXML.hash2xml({ tag1: { tag2: 'content' } }, indent: 2)
# =>
# <?xml version="1.0" encoding="utf-8"?>
# <root>
# <tag1>
# <tag2>content</tag2>
# </tag1>
# </root>
# use enumerator
FastXML.hash2xml({ enumerator: 3.times }, indent: 2)
# =>
# <?xml version="1.0" encoding="utf-8"?>
# <root>
# <enumerator>0</enumerator>
# <enumerator>1</enumerator>
# <enumerator>2</enumerator>
# </root>
# output to file handle
# fh = StringIO.new
FastXML.hash2xml({ enumerator: 3.times }, indent: 2, output: fh)
fh.string
# =>
# <?xml version="1.0" encoding="utf-8"?>
# <root>
# <enumerator>0</enumerator>
# <enumerator>1</enumerator>
# <enumerator>2</enumerator>
# </root>
Convert XML to hash
FastXML.xml2hash('<root><a>aaa</a><a>aaa2</a><b attr="bbb">bbb2</b></root>')
# => {"a"=>["aaa", "aaa2"], "b"=>{"attr"=>"bbb", "content"=>"bbb2"}}
# use filter
FastXML.xml2hash('<root><a>aaa</a><a>aaa2</a><b>bbb</b></root>', filter: '/root/a') do |node|
p node
end
# =>
# {"a"=>"aaa"}
# {"a"=>"aaa2"}
Options
The following options are available to pass to FastXML.hash2xml(hash, options = {}).
:root => 'root' # hash2xml
- Root node name.
:version => '1.0' # hash2xml
- XML document version
:encoding => 'utf-8' # hash2xml + xml2hash
- XML input/output encoding
:indent => 0 # hash2xml
- if indent great than 0, XML output should be indented according to its hierarchic structure. This value determines the number of spaces.
- if indent is 0, XML output will all be on one line.
:output => nil # hash2xml
- XML output method
- if output is nil, XML document dumped into string.
- if output is filehandle, XML document writes directly to a filehandle or a stream.
:canonical => false # hash2xml
- if canonical is true, the converter will be write hashes sorted by key.
- if canonical is false, the order of the element will be pseudo-randomly.
:use_attr => false # hash2xml
- if use_attr is true, the converter will be use the attributes.
- if use_attr is fale, the converter will be use tags only.
:content => 'content' # hash2xml + xml2hash
- The key name for the text content.
:force_array => nil # xml2hash
- When this option is true, the converter will be to force nested elements to be represented as arrays even when there is only one.
FastXML.xml2hash('<root><a>aaa</a></root>', force_array: true)
will be converted to:
{ "a" => ["aaa"] }
instead of:
{ "a" => "aaa" }
- When this option is an array, this allows to specify a list of element names which should always be forced into an array representation, rather than the 'all or nothing' approach above.
FastXML.xml2hash('<root><a>aaa</a><b>bbb</b></root>', force_array: ['a'])
will be converted to:
{ "a" => ["aaa"], "b" => "bbb" }
FastXML.xml2hash('<root><a>aaa</a><a2>aaa</a2><b>bbb</b></root>', force_array: [/^a/])
will be converted to:
{ "a" => ["aaa"], "a2" => ["aaa"], "b" => "bbb" }
:force_content => false # xml2hash
- When this options is true, this allows you to force text content to always convert to a hash value.
FastXML.xml2hash('<root><a>value</a></root>', force_content: true)
will be converted to:
{ "a" => { "content" => "value" } }
instead of:
{ "a" => "value" }
:merge_text => false # xml2hash
- Setting this option to true will cause merge adjacent text nodes.
FastXML.xml2hash('<root>value1<!-- comment -->value2</root>', merge_text: true)
will be converted to:
instead of: ```["value1", "value2"]```
:xml_decl => true # hash2xml
- if xml_decl is true, output will start with the XML declaration
<?xml version="1.0" encoding="utf-8"?>
- if xml_decl is false, XML declaration will not be output.
- if xml_decl is true, output will start with the XML declaration
:trim => false # hash2xml + xml2hash
- Trim leading and trailing whitespace from text nodes.
:utf8 => true # hash2xml + xml2hash
- Turn on utf8 flag for strings if is true.
:max_depth => 1024 # xml2hash
- Maximum recursion depth.
:buf_size => 4096 # hash2xml + xml2hash
- Buffer size for reading end encoding data.
:keep_root => false # xml2hash
- Keep root element.
FastXML.xml2hash('<root>value1</root>', keep_root: true)
will be converted to:
{ "root" => "value1" }
instead of:
</code>
:filter => nil # xml2hash
- Filter nodes matched by pattern and return an array of nodes.
FastXML.xml2hash('<root><a>aaa</a><a>aaa2</a><b>bbb</b></root>', filter: '/root/a')
will be converted to:
[{ "a" => "aaa" }, { "a" => "aaa2" }]
FastXML.xml2hash('<root><a>aaa</a><a>aaa2</a><b>bbb</b></root>', filter: /a|b/)
will be converted to:
[{ "a" => "aaa" }, { "a" => "aaa2" }, { "b" => "bbb" }]
FastXML.xml2hash('<root><a>aaa</a><a>aaa2</a><b>bbb</b></root>', filter: ['/root/a', '/root/b'])
will be converted to:
[{ "a" => "aaa" }, { "a" => "aaa2" }, { "b" => "bbb" }]
- You can pass a block as parameter.
FastXML.xml2hash('<root><a>aaa</a><a>aaa2</a><b>bbb</b></root>', filter: '/root/a') do |node| p node end
will be printed:
{"a"=>"aaa"} {"a"=>"aaa2"}
It may be used to parse large XML because does not require a lot of memory.
Configuration
FastXML.configure do |config|
config.trim = true
end
Benchmarks
Performance benchmark in comparison with some popular gems:
Converting Hash to XML:
user system total real
activesupport(rexml) 10.920000 0.010000 10.930000 ( 10.948205)
activesupport(libxml) 10.880000 0.000000 10.880000 ( 10.910649)
activesupport(nokogiri) 10.880000 0.000000 10.880000 ( 10.899013)
xmlsimple 1.490000 0.000000 1.490000 ( 1.504655)
fastxml 0.020000 0.000000 0.020000 ( 0.018095)
Converting XML to Hash:
user system total real
activesupport(rexml) 8.420000 0.000000 8.420000 ( 8.441763)
activesupport(libxml) 1.110000 0.010000 1.120000 ( 1.109242)
activesupport(nokogiri) 1.660000 0.000000 1.660000 ( 1.666208)
xmlsimple 8.390000 0.010000 8.400000 ( 8.427240)
nori 2.010000 0.000000 2.010000 ( 2.016399)
xmlhasher 0.440000 0.000000 0.440000 ( 0.433211)
fastxml 0.070000 0.000000 0.070000 ( 0.073124)
License
The gem is available as open source under the terms of the MIT License.