== Element Context

Notes:
- All code on this page presupposes that the following has been executed:

    require 'rexml/document'

- For convenience, examples on this page use +REXML::Document.new+, not +REXML::Element.new+.
  This is completely valid, because REXML::Document is a subclass of REXML::Element.

The context for an element is a hash of processing directives
that influence the way \XML is read, stored, and written.
The context entries are:

- +:respect_whitespace+: controls treatment of whitespace.
- +:compress_whitespace+: determines whether whitespace is compressed.
- +:ignore_whitespace_nodes+: determines whether whitespace-only nodes are to be ignored.
- +:raw+: controls treatment of special characters and entities.

The default context for a new element is <tt>{}</tt>.
You can set the context at element-creation time:

  d = REXML::Document.new('', {compress_whitespace: :all, raw: :all})
  d.context # => {:compress_whitespace=>:all, :raw=>:all}

You can reset the entire context by assigning a new hash:

  d.context = {ignore_whitespace_nodes: :all}
  d.context # => {:ignore_whitespace_nodes=>:all}

Or you can create or modify an individual entry:

  d.context[:raw] = :all
  d.context # => {:ignore_whitespace_nodes=>:all, :raw=>:all}

=== +:respect_whitespace+

Affects: +REXML::Element.new+, +REXML::Element.text=+.

By default, all parsed whitespace is respected (that is, stored whitespace not compressed):

  xml_string = '<root><foo>a   b</foo>    <bar>c   d</bar>   <baz>e   f</baz></root>'
  d = REXML::Document.new(xml_string)
  d.to_s # => "<root><foo>a   b</foo>    <bar>c   d</bar>   <baz>e   f</baz></root>"

Use +:respect_whitespace+ with an array of element names
to specify the elements that _are_ to have their whitespace respected;
other elements' whitespace, and whitespace between elements, will be compressed.

In this example: +foo+ and +baz+ will have their whitespace respected;
+bar+ and the space between elements will have their whitespace compressed:

  d = REXML::Document.new(xml_string, {respect_whitespace: ['foo', 'baz']})
  d.to_s # => "<root><foo>a   b</foo> <bar>c d</bar> <baz>e   f</baz></root>"
  bar = d.root[2] # => <bar> ... </>
  bar.text = 'X   Y'
  d.to_s # => "<root><foo>a   b</foo> <bar>X Y</bar> <baz>e   f</baz></root>"

=== +:compress_whitespace+

Affects: +REXML::Element.new+, +REXML::Element.text=+.

Use <tt>compress_whitespace: :all</tt>
to compress whitespace both within and between elements:

  xml_string = '<root><foo>a   b</foo>    <bar>c   d</bar>   <baz>e   f</baz></root>'
  d = REXML::Document.new(xml_string, {compress_whitespace: :all})
  d.to_s # => "<root><foo>a b</foo> <bar>c d</bar> <baz>e f</baz></root>"

Use +:compress_whitespace+ with an array of element names
to compress whitespace in those elements,
but not in other elements nor between elements.

In this example, +foo+ and +baz+ will have their whitespace compressed;
+bar+ and the space between elements will not:

  d = REXML::Document.new(xml_string, {compress_whitespace: ['foo', 'baz']})
  d.to_s # => "<root><foo>a b</foo>    <bar>c   d</bar>   <baz>e f</baz></root>"
  foo = d.root[0] # => <foo> ... </>
  foo.text= 'X   Y'
  d.to_s # => "<root><foo>X Y</foo>    <bar>c   d</bar>   <baz>e f</baz></root>"

=== +:ignore_whitespace_nodes+

Affects: +REXML::Element.new+.

Use <tt>ignore_whitespace_nodes: :all</tt> to omit all whitespace-only elements.

In this example, +bar+ has a text node, while nodes +foo+ and +baz+ do not:

  xml_string = '<root><foo>   </foo><bar> BAR </bar><baz>   </baz></root>'
  d = REXML::Document.new(xml_string, {ignore_whitespace_nodes: :all})
  d.to_s # => "<root><foo> FOO </foo><bar/><baz> BAZ </baz></root>"
  root = d.root   # => <root> ... </>
  foo = root[0]   # => <foo/>
  bar = root[1]   # => <bar> ... </>
  baz = root[2]   # => <baz/>
  foo.first.class # => NilClass
  bar.first.class # => REXML::Text
  baz.first.class # => NilClass

Use +:ignore_whitespace_nodes+ with an array of element names
to specify the elements that are to have whitespace nodes ignored.

In this example, +bar+ and +baz+ have text nodes, while node +foo+ does not.

  xml_string = '<root><foo>   </foo><bar> BAR </bar><baz>   </baz></root>'
  d = REXML::Document.new(xml_string, {ignore_whitespace_nodes: ['foo']})
  d.to_s # => "<root><foo/><bar> BAR </bar><baz>   </baz></root>"
  root = d.root   # => <root> ... </>
  foo = root[0]   # => <foo/>
  bar = root[1]   # => <bar> ... </>
  baz = root[2]   # => <baz> ... </>
  foo.first.class # => NilClass
  bar.first.class # => REXML::Text
  baz.first.class # => REXML::Text

=== +:raw+

Affects:  +Element.text=+, +Element.add_text+, +Text.to_s+.

Parsing of +a+ elements is not affected by +raw+:

  xml_string = '<root><a>0 &lt; 1</a><b>1 &gt; 0</b></root>'
  d = REXML::Document.new(xml_string, {:raw => ['a']})
  d.root.to_s # => "<root><a>0 &lt; 1</a><b>1 &gt; 0</b></root>"
  a, b = *d.root.elements
  a.to_s # => "<a>0 &lt; 1</a>"
  b.to_s # => "<b>1 &gt; 0</b>"

But Element#text= is affected:

  a.text = '0 &lt; 1'
  b.text = '1 &gt; 0'
  a.to_s # => "<a>0 &lt; 1</a>"
  b.to_s # => "<b>1 &amp;gt; 0</b>"

As is Element.add_text:

  a.add_text(' so 1 &gt; 0')
  b.add_text(' so 0 &lt; 1')
  a.to_s # => "<a>0 &lt; 1 so 1 &gt; 0</a>"
  b.to_s # => "<b>1 &amp;gt; 0 so 0 &amp;lt; 1</b>"
