File: tmstd/xml.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: TmStd#8
  module: Xml#10
has properties
constant: XML_DECL #11
constant: XINCLUDE_XMLNS #12
constant: EMPTY_SEQ_OF_UNIT #239
  module: Abstraction#15
  class: Unit#17
includes
  Treeable ( TmStd )
inherits from
  Abstract ( TmStd::Lsm::Product )
has properties
method: to_s #21
method: __print_tree__ / 7 #26
method: __print_tree_indent__ / 2 #50
  class: TextUnit#64
inherits from
  Unit ( TmStd::Xml::Abstraction )
has properties
method: each / 1 #65
method: children #66
method: empty? #67
method: to_s #70
  class: Identifier#77
inherits from
  Abstract ( TmStd::Lsm::Product )
has properties
attribute: name [R] #78
attribute: xmlns [R] #78
attribute: hash [R] #79
method: initialize / 2 #82
method: to_s #96
method: eql? / 1 #107
method: freeze_equality! #116
  class: Text#126
inherits from
  TextUnit ( TmStd::Xml::Abstraction )
has properties
attribute: text [R] #127
method: initialize / 1 #130
method: to_s #139
  class: RawString#152
inherits from
  String ( Builtin-Module )
  class: RawText#156
inherits from
  TextUnit ( TmStd::Xml::Abstraction )
has properties
attribute: text [R] #157
method: initialize / 1 #160
method: to_s #169
  class: Tag#176
inherits from
  Identifier ( TmStd::Xml::Abstraction )
  module: Attribute#180
has properties
constant: EMPTY_MAP #228
  class: Key#182
inherits from
  Identifier ( TmStd::Xml::Abstraction )
  class: Map#186
inherits from
  Abstract ( TmStd::Lsm::Collection::Map )
has properties
constant: LSM_DOMAIN_CLASS #187
constant: LSM_RANGE_CLASS #188
method: to_s #191
  class: SeqOfUnit#235
inherits from
  Abstract ( TmStd::Lsm::Collection::Sequence )
has properties
constant: LSM_ELEMENT_CLASS #236
  class: Element#243
includes
  Enumerable ( Builtin-Module )
inherits from
  Unit ( TmStd::Xml::Abstraction )
has properties
attribute: tag [R] #246
attribute: xmlns [R] #247
attribute: attribute_map [R] #248
attribute: seq_of_unit [R] #249
alias: attributes attribute_map #252
alias: children seq_of_unit #253
method: initialize / 4 #256
method: in_verbatim? #331
method: empty? #336
method: each / 1 #341
method: to_s / 1 #348
method: __print_tree__ / 7 #373
method: __print_tree_enter__ / 2 #426
method: __print_tree_leave__ / 2 #433
  class: Document#450
inherits from
  Element ( TmStd::Xml )
has properties
attribute: doc_type [R] #451
method: initialize / 5 #454
method: __print_tree_enter__ / 2 #466
  class: Include#477
inherits from
  Element ( TmStd::Xml )
has properties
method: initialize / 1 #478

Code

   1  # $Id: xml.rb,v 1.8 2012/04/17 02:49:40 machan Exp $
   2 
   3  require 'tmdoc/tmstd'
   4  require 'tmdoc/tmstd/treeable'
   5  require 'tmdoc/tmstd/lsm'
   6 
   7 
   8  module TmStd
   9 
  10  module Xml
  11      XML_DECL = '<?xml version="1.0" encoding="UTF-8" standalone="no"?>'
  12      XINCLUDE_XMLNS = 'http://www.w3.org/2001/XInclude'
  13 
  14 
  15  module Abstraction
  16 
  17  class Unit < TmStd::Lsm::Product::Abstract
  18      include TmStd::Treeable
  19 
  20 
  21      def to_s
  22          raise TmStd::Exception::SubclassResponsibility
  23      end
  24 
  25 
  26      def __print_tree__(
  27          io, depth, in_verbatim, rejector, selector, do_sort, comparator
  28      )
  29          Assertion.kind_of   depth,          Integer
  30          Assertion.boolean   in_verbatim
  31          Assertion.nil       rejector,       "Not implemented"
  32          Assertion.nil       selector,       "Not implemented"
  33          Assertion.boolean   do_sort
  34          Assertion.nil       comparator,     "Not implemented"
  35 
  36          Assertion.assert    ! do_sort,      "Not implemented"
  37 
  38          if in_verbatim
  39              io << self.to_s
  40          else
  41              __print_tree_indent__(io, depth)
  42 
  43              io << self.to_s << "\n"
  44          end
  45 
  46          nil
  47      end
  48 
  49 
  50      def __print_tree_indent__(io, depth)
  51          Assertion.kind_of depth,    Integer
  52 
  53          if depth > 0
  54              io << "\t" * depth
  55          end
  56 
  57          nil
  58      end
  59      private :__print_tree_indent__
  60  end
  61 
  62 
  63 
  64  class TextUnit < Unit
  65      def each(&block);                       end     # Nothing to do.
  66      def children;       EMPTY_SEQ_OF_UNIT;  end     # Empty sequence.
  67      def empty?;         true;               end     # Anytime empty.
  68 
  69 
  70      def to_s
  71          raise TmStd::Exception::SubclassResponsibility
  72      end
  73  end
  74 
  75 
  76 
  77  class Identifier < TmStd::Lsm::Product::Abstract
  78      attr_reader :name, :xmlns
  79      attr_reader :hash
  80 
  81 
  82      def initialize(name, xmlns = nil)
  83          Assertion.kind_of       name,   Symbol
  84          Assertion.opt_kind_of   xmlns,  Symbol
  85 
  86          @name   = name
  87          @xmlns  = xmlns
  88 
  89          @name.freeze
  90          @xmlns.freeze
  91 
  92          @hash = self.to_s.hash
  93      end
  94 
  95 
  96      def to_s
  97          str =   if @xmlns
  98                      format("%s:%s", @xmlns.to_s, @name.to_s)
  99                  else
 100                      @name.to_s
 101                  end
 102 
 103          Assertion.kind_of str, String
 104      end
 105 
 106 
 107      def eql?(other)
 108          Assertion.kind_of other, self.class
 109 
 110          result = @name == other.name && @xmlns == other.xmlns
 111 
 112          Assertion.boolean result
 113      end
 114 
 115 
 116      def freeze_equality!
 117          nil     # Nop, already frozen.
 118      end
 119  end
 120 
 121 
 122  end
 123 
 124 
 125 
 126  class Text < Abstraction::TextUnit
 127      attr_reader :text
 128 
 129 
 130      def initialize(str)
 131          Assertion.kind_of str, String
 132 
 133          super()
 134 
 135          @text = str
 136      end
 137 
 138 
 139      def to_s
 140          str = @text.dup
 141          str.gsub!(/&/,  '&amp;')
 142          str.gsub!(/\"/, '&quot;')
 143          str.gsub!(/</,  '&lt;')
 144          str.gsub!(/>/,  '&gt;')
 145 
 146          Assertion.kind_of str, String
 147      end
 148  end
 149 
 150 
 151 
 152  class RawString < String; end
 153 
 154 
 155 
 156  class RawText < Abstraction::TextUnit
 157      attr_reader :text
 158 
 159 
 160      def initialize(str)
 161          Assertion.kind_of str, String
 162 
 163          super()
 164 
 165          @text = RawString.new str
 166      end
 167 
 168 
 169      def to_s
 170          Assertion.kind_of @text, String
 171      end
 172  end
 173 
 174 
 175 
 176  class Tag < Abstraction::Identifier; end
 177 
 178 
 179 
 180  module Attribute
 181 
 182  class Key < Abstraction::Identifier; end
 183 
 184 
 185 
 186  class Map < TmStd::Lsm::Collection::Map::Abstract
 187      LSM_DOMAIN_CLASS    = Attribute::Key
 188      LSM_RANGE_CLASS     = String
 189 
 190 
 191      def to_s
 192          str = self.map { |key, value|
 193              format(
 194                  "%s=\"%s\"",
 195 
 196                  key.to_s,
 197 
 198                  case value
 199                  when RawString
 200                      value
 201                  when String
 202                      val = value.dup
 203 
 204                      val.gsub!(/%/,  '%%')
 205                      val.gsub!(/ /,  '%20')
 206                      val.gsub!(/\"/, '%22')
 207                      val.gsub!(/#/,  '%23')
 208                      val.gsub!(/&/,  '%26')
 209                      val.gsub!(/\//, '%2f')
 210                      val.gsub!(/:/,  '%3a')
 211                      val.gsub!(/</,  '%3c')
 212                      val.gsub!(/>/,  '%3e')
 213 
 214                      val
 215                  else
 216                      Assertion.abort(
 217                          "Unexpected value: '%s' (%s)",
 218                          value.to_s, value.class.to_s
 219                      )
 220                  end
 221              )
 222          }.join(' ')
 223 
 224          Assertion.kind_of str, String
 225      end
 226  end
 227 
 228  EMPTY_MAP = Map.new
 229 
 230  end
 231 
 232 
 233 
 234 
 235  class SeqOfUnit < TmStd::Lsm::Collection::Sequence::Abstract
 236      LSM_ELEMENT_CLASS = Abstraction::Unit
 237  end
 238 
 239  EMPTY_SEQ_OF_UNIT = SeqOfUnit.new
 240 
 241 
 242 
 243  class Element < Abstraction::Unit
 244      include     Enumerable
 245 
 246      attr_reader :tag,
 247                  :xmlns,
 248                  :attribute_map,
 249                  :seq_of_unit
 250 
 251 
 252      alias :attributes   :attribute_map
 253      alias :children     :seq_of_unit
 254 
 255 
 256      def initialize(tag, attrs = {}, opts = {}, &block)
 257          Assertion.kind_of tag,      Symbol
 258          Assertion.kind_of attrs,    Hash
 259          Assertion.kind_of opts,     Hash
 260 
 261          super()
 262 
 263          @tag            = tag
 264          @xmlns          = nil
 265          @in_verbatim    = false
 266 
 267          for key, val in opts
 268              Assertion.kind_of key, Symbol
 269 
 270              case key
 271              when :xmlns
 272                  Assertion.kind_of val, Symbol
 273 
 274                  @xmlns          = val
 275              when :in_verbatim
 276                  Assertion.boolean val
 277 
 278                  @in_verbatim    = val
 279              else
 280                  Assertion.abort "Unknown option: %s", key
 281              end
 282          end
 283 
 284          @attribute_map =
 285              unless attrs.empty?
 286                  Attribute::Map.new(
 287                      attrs.inject({}) { |hash_of_attr, pair|
 288                          Assertion.tuple_of pair, [Object, String]
 289                          key, val =  pair
 290 
 291                          hash_key =
 292                              case key
 293                              when Symbol
 294                                  Attribute::Key.new(key)
 295                              when Attribute::Key
 296                                  key
 297                              else
 298                                  Assertion.abort(
 299                                      "Expected Symbol or Key, " +
 300                                          "but attribute key <%s> was a <%s>",
 301                                      key.to_s, key.class.to_s
 302                                  )
 303                              end
 304 
 305                          hash_of_attr.merge(hash_key => val) {
 306                              Assertion.abort(
 307                                  "Duplicated attribute key: %s", key.to_s
 308                              )
 309                          }
 310                      }
 311                  )
 312              else
 313                  Attribute::EMPTY_MAP
 314              end
 315 
 316          @seq_of_unit =  if block
 317                              array_of_unit = block.call
 318                              Assertion.kind_of array_of_unit, Array
 319 
 320                              unless array_of_unit.empty?
 321                                  SeqOfUnit.new(array_of_unit)
 322                              else
 323                                  EMPTY_SEQ_OF_UNIT
 324                              end
 325                          else
 326                              EMPTY_SEQ_OF_UNIT
 327                          end
 328      end
 329 
 330 
 331      def in_verbatim?
 332          Assertion.boolean @in_verbatim
 333      end
 334 
 335 
 336      def empty?
 337          Assertion.boolean self.children.empty?
 338      end
 339 
 340 
 341      def each(&block)
 342          self.children.each(&block)
 343 
 344          nil
 345      end
 346 
 347 
 348      def to_s(has_child = false)
 349          str = format("<%s%s%s",
 350              if self.xmlns
 351                  format "%s:%s", self.xmlns.to_s, self.tag.to_s
 352              else
 353                  self.tag.to_s
 354              end,
 355 
 356              if self.attributes.empty?
 357                  ''
 358              else
 359                  ' ' + self.attributes.to_s
 360              end,
 361 
 362              if has_child
 363                  '>'
 364              else
 365                  '/>'
 366              end
 367          )
 368 
 369          Assertion.kind_of str, String
 370      end
 371 
 372 
 373      def __print_tree__(
 374          io, depth, in_verbatim, rejector, selector, do_sort, comparator
 375      )
 376          Assertion.kind_of   depth,          Integer
 377          Assertion.boolean   in_verbatim
 378          Assertion.nil       rejector,       "Not implemented"
 379          Assertion.nil       selector,       "Not implemented"
 380          Assertion.boolean   do_sort
 381          Assertion.nil       comparator,     "Not implemented"
 382 
 383          Assertion.assert    ! do_sort,      "Not implemented"
 384 
 385          has_child   = (! self.empty?)
 386 
 387          unless in_verbatim
 388              __print_tree_indent__(io, depth)
 389          end
 390 
 391          self.__print_tree_enter__(io, has_child)
 392 
 393          if has_child
 394              unless in_verbatim || self.in_verbatim?
 395                  io << "\n"
 396              end
 397 
 398              for child in self
 399                  Assertion.kind_of(child, Abstraction::Unit,
 400                      "The child of %s '%s' isn't XML unit",
 401                      self.class,
 402                      self.to_s
 403                  )
 404 
 405                  child.__print_tree__(
 406                      io, depth + 1, in_verbatim || self.in_verbatim?,
 407                      rejector, selector, do_sort, comparator
 408                  )
 409              end
 410 
 411              unless in_verbatim || self.in_verbatim?
 412                  __print_tree_indent__(io, depth)
 413              end
 414          end
 415 
 416          self.__print_tree_leave__(io, has_child)
 417 
 418          unless in_verbatim
 419              io << "\n"
 420          end
 421 
 422          nil
 423      end
 424 
 425 
 426      def __print_tree_enter__(io, has_child)
 427          io << self.to_s(has_child)
 428 
 429          nil
 430      end
 431 
 432 
 433      def __print_tree_leave__(io, has_child)
 434          if has_child
 435              io.printf("</%s>",
 436                  if self.xmlns
 437                      format "%s:%s", self.xmlns, self.tag
 438                  else
 439                      self.tag
 440                  end
 441              )
 442          end
 443 
 444          nil
 445      end
 446  end
 447 
 448 
 449 
 450  class Document < Element
 451      attr_reader     :doc_type
 452 
 453 
 454      def initialize(tag, doc_type, attrs = {}, opts = {}, &block)
 455          Assertion.kind_of tag,      Symbol
 456          Assertion.kind_of doc_type, String
 457          Assertion.kind_of attrs,    Hash
 458          Assertion.kind_of opts,     Hash
 459 
 460          super(tag, attrs, opts, &block)
 461 
 462          @doc_type = doc_type
 463      end
 464 
 465 
 466      def __print_tree_enter__(io, has_child)
 467          io.printf "%s\n\n%s\n\n\n", XML_DECL, self.doc_type
 468 
 469          super
 470 
 471          nil
 472      end
 473  end
 474 
 475 
 476 
 477  class Include < Element
 478      def initialize(path)
 479          Assertion.kind_of path, String
 480 
 481          super(
 482              :include,
 483              {
 484                  Attribute::Key.new(:xi, :xmlns) =>
 485                      RawString.new(XINCLUDE_XMLNS),
 486                  :href => RawString.new(path)
 487              },
 488              :xmlns => :xi
 489          )
 490      end
 491  end
 492 
 493  end # TmStd::Xml
 494 
 495  end # TmStd