File: rexml/doctype.rb

Overview
Module Structure
Class Hierarchy
Code

Overview

Module Structure

  module: <Toplevel Module>
  module: REXML#8
  class: DocType#12
includes
  XMLTokens ( REXML )
inherits from
  Parent ( REXML )
has properties
constant: START #14
constant: STOP #15
constant: SYSTEM #16
constant: PUBLIC #17
constant: DEFAULT_ENTITIES #18
attribute: name [R] #27
attribute: external_id [R] #27
attribute: entities [R] #27
attribute: namespaces [R] #27
method: initialize / 2 #41
method: node_type #70
method: attributes_of #74
method: attribute_of #84
method: clone #94
method: write / 4 #108
method: context #130
method: entity / 1 #134
method: add #138
method: public #148
method: system #160
method: notations #174
method: notation / 1 #182
method: strip_quotes / 1 #191
  class: Declaration#204
inherits from
  Child ( REXML )
has properties
method: initialize #205
method: to_s #210
method: write / 2 #217
  class: ElementDecl#223
inherits from
  Declaration ( REXML )
has properties
method: initialize / 1 #224
  class: ExternalEntity#229
inherits from
  Child ( REXML )
has properties
method: initialize / 1 #230
method: to_s #234
method: write / 2 #237
  class: NotationDecl#242
inherits from
  Child ( REXML )
has properties
attribute: public [RW] #243
attribute: system [RW] #243
method: initialize #244
method: to_s #252
method: write / 2 #260
method: name #267

Class Hierarchy

Object ( Builtin-Module )
Child ( REXML )
Declaration ( REXML ) — #204
  ElementDecl    #223
ExternalEntity ( REXML ) — #229
NotationDecl ( REXML ) — #242
Parent ( REXML )
  DocType    #12

Code

   1  require "rexml/parent"
   2  require "rexml/parseexception"
   3  require "rexml/namespace"
   4  require 'rexml/entity'
   5  require 'rexml/attlistdecl'
   6  require 'rexml/xmltokens'
   7 
   8  module REXML
   9    # Represents an XML DOCTYPE declaration; that is, the contents of <!DOCTYPE
  10    # ... >.  DOCTYPES can be used to declare the DTD of a document, as well as
  11    # being used to declare entities used in the document.
  12    class DocType < Parent
  13      include XMLTokens
  14      START = "<!DOCTYPE"
  15      STOP = ">"
  16      SYSTEM = "SYSTEM"
  17      PUBLIC = "PUBLIC"
  18      DEFAULT_ENTITIES = { 
  19        'gt'=>EntityConst::GT, 
  20        'lt'=>EntityConst::LT, 
  21        'quot'=>EntityConst::QUOT, 
  22        "apos"=>EntityConst::APOS 
  23      }
  24 
  25      # name is the name of the doctype
  26      # external_id is the referenced DTD, if given
  27      attr_reader :name, :external_id, :entities, :namespaces
  28 
  29      # Constructor
  30      #
  31      #   dt = DocType.new( 'foo', '-//I/Hate/External/IDs' )
  32      #   # <!DOCTYPE foo '-//I/Hate/External/IDs'>
  33      #   dt = DocType.new( doctype_to_clone )
  34      #   # Incomplete.  Shallow clone of doctype
  35      #
  36      # +Note+ that the constructor: 
  37      #
  38      #  Doctype.new( Source.new( "<!DOCTYPE foo 'bar'>" ) )
  39      #
  40      # is _deprecated_.  Do not use it.  It will probably disappear.
  41      def initialize( first, parent=nil )
  42        @entities = DEFAULT_ENTITIES
  43        @long_name = @uri = nil
  44        if first.kind_of? String
  45          super()
  46          @name = first
  47          @external_id = parent
  48        elsif first.kind_of? DocType
  49          super( parent )
  50          @name = first.name
  51          @external_id = first.external_id
  52        elsif first.kind_of? Array
  53          super( parent )
  54          @name = first[0]
  55          @external_id = first[1]
  56          @long_name = first[2]
  57          @uri = first[3]
  58        elsif first.kind_of? Source
  59          super( parent )
  60          parser = Parsers::BaseParser.new( first )
  61          event = parser.pull
  62          if event[0] == :start_doctype
  63            @name, @external_id, @long_name, @uri, = event[1..-1]
  64          end
  65        else
  66          super()
  67        end
  68      end
  69 
  70      def node_type
  71        :doctype
  72      end
  73 
  74      def attributes_of element
  75        rv = []
  76        each do |child|
  77          child.each do |key,val|
  78            rv << Attribute.new(key,val)
  79          end if child.kind_of? AttlistDecl and child.element_name == element
  80        end
  81        rv
  82      end
  83 
  84      def attribute_of element, attribute
  85        att_decl = find do |child|
  86          child.kind_of? AttlistDecl and
  87          child.element_name == element and
  88          child.include? attribute
  89        end
  90        return nil unless att_decl
  91        att_decl[attribute]
  92      end
  93 
  94      def clone
  95        DocType.new self
  96      end
  97 
  98      # output::
  99      #   Where to write the string
 100      # indent::
 101      #   An integer.  If -1, no indentation will be used; otherwise, the
 102      #   indentation will be this number of spaces, and children will be
 103      #   indented an additional amount.
 104      # transitive::
 105      #   Ignored
 106      # ie_hack::
 107      #   Ignored
 108      def write( output, indent=0, transitive=false, ie_hack=false )
 109        f = REXML::Formatters::Default.new
 110        indent( output, indent )
 111        output << START
 112        output << ' '
 113        output << @name
 114        output << " #@external_id" if @external_id
 115        output << " #{@long_name.inspect}" if @long_name
 116        output << " #{@uri.inspect}" if @uri
 117        unless @children.empty?
 118          next_indent = indent + 1
 119          output << ' ['
 120          child = nil    # speed
 121          @children.each { |child|
 122            output << "\n"
 123            f.write( child, output )
 124          }
 125          output << "\n]"
 126        end
 127        output << STOP
 128      end
 129 
 130      def context
 131        @parent.context
 132      end
 133 
 134      def entity( name )
 135        @entities[name].unnormalized if @entities[name]
 136      end
 137 
 138      def add child
 139        super(child)
 140        @entities = DEFAULT_ENTITIES.clone if @entities == DEFAULT_ENTITIES
 141        @entities[ child.name ] = child if child.kind_of? Entity
 142      end
 143      
 144      # This method retrieves the public identifier identifying the document's 
 145      # DTD.
 146      #
 147      # Method contributed by Henrik Martensson
 148      def public
 149        case @external_id
 150        when "SYSTEM"
 151          nil
 152        when "PUBLIC"
 153          strip_quotes(@long_name)
 154        end
 155      end
 156      
 157      # This method retrieves the system identifier identifying the document's DTD
 158      #
 159      # Method contributed by Henrik Martensson
 160      def system
 161        case @external_id
 162        when "SYSTEM"
 163          strip_quotes(@long_name)
 164        when "PUBLIC"
 165          @uri.kind_of?(String) ? strip_quotes(@uri) : nil
 166        end
 167      end
 168      
 169      # This method returns a list of notations that have been declared in the
 170      # _internal_ DTD subset. Notations in the external DTD subset are not 
 171      # listed.
 172      #
 173      # Method contributed by Henrik Martensson
 174      def notations
 175        children().select {|node| node.kind_of?(REXML::NotationDecl)}
 176      end
 177      
 178      # Retrieves a named notation. Only notations declared in the internal
 179      # DTD subset can be retrieved.
 180      #
 181      # Method contributed by Henrik Martensson
 182      def notation(name)
 183        notations.find { |notation_decl|
 184          notation_decl.name == name
 185        }
 186      end
 187      
 188      private
 189      
 190      # Method contributed by Henrik Martensson
 191      def strip_quotes(quoted_string)
 192        quoted_string =~ /^[\'\"].*[\´\"]$/ ?
 193          quoted_string[1, quoted_string.length-2] :
 194          quoted_string
 195      end
 196    end
 197 
 198    # We don't really handle any of these since we're not a validating
 199    # parser, so we can be pretty dumb about them.  All we need to be able
 200    # to do is spew them back out on a write()
 201 
 202    # This is an abstract class.  You never use this directly; it serves as a
 203    # parent class for the specific declarations.
 204    class Declaration < Child
 205      def initialize src
 206        super()
 207        @string = src
 208      end
 209 
 210      def to_s
 211        @string+'>'
 212      end
 213 
 214      # == DEPRECATED
 215      # See REXML::Formatters
 216      #
 217      def write( output, indent )
 218        output << to_s
 219      end
 220    end
 221    
 222    public
 223    class ElementDecl < Declaration
 224      def initialize( src )
 225        super
 226      end
 227    end
 228 
 229    class ExternalEntity < Child
 230      def initialize( src )
 231        super()
 232        @entity = src
 233      end
 234      def to_s
 235        @entity
 236      end
 237      def write( output, indent )
 238        output << @entity
 239      end
 240    end
 241 
 242    class NotationDecl < Child
 243      attr_accessor :public, :system
 244      def initialize name, middle, pub, sys
 245        super(nil)
 246        @name = name
 247        @middle = middle
 248        @public = pub
 249        @system = sys
 250      end
 251 
 252      def to_s
 253        "<!NOTATION #@name #@middle#{
 254          @public ? ' ' + public.inspect : '' 
 255        }#{
 256          @system ? ' ' +@system.inspect : ''
 257        }>"
 258      end
 259 
 260      def write( output, indent=-1 )
 261        output << to_s
 262      end
 263      
 264      # This method retrieves the name of the notation.
 265      #
 266      # Method contributed by Henrik Martensson
 267      def name
 268        @name
 269      end
 270    end
 271  end