Package pywbem :: Module cimxml_parse |
[frames] | no frames]

# Source Code for Module pywbem.cimxml_parse

      1  #
      2  # (C) Copyright 2006,2007 Hewlett-Packard Development Company, L.P.
      3  #
      4  # This library is free software; you can redistribute it and/or
      5  # modify it under the terms of the GNU Lesser General Public
      6  # License as published by the Free Software Foundation; either
      7  # version 2.1 of the License, or (at your option) any later version.
      8  #
      9  # This program is distributed in the hope that it will be useful, but
     10  # WITHOUT ANY WARRANTY; without even the implied warranty of
     11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  # Lesser General Public License for more details.
     13  #
     14  # You should have received a copy of the GNU Lesser General Public
     15  # License along with this program; if not, write to the Free Software
     16  # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     17  #
     18  # Author: Tim Potter <tpot@hp.com>
     19  #
     20
     21  import string
     22  from xml.dom import pulldom
     23
     24  from pywbem import cim_obj
     25  from pywbem.cim_obj import CIMInstance, CIMInstanceName, CIMQualifier, \
     26                             CIMProperty
     27
     28  __all__ = ['ParseError', 'make_parser', 'parse_any']
     29
     30 -class ParseError(Exception):
     31      """This exception is raised when there is a validation error detected
     32      by the parser."""
     33      pass
     34
     35  #
     36  # Helper functions
     37  #
     38
     39 -def _get_required_attribute(node, attr):
     40      """Return an attribute by name.  Throw an exception if not present."""
     41
     42      if not node.hasAttribute(attr):
     43          raise ParseError(
     44              'Expecting %s attribute in element %s' % (attr, node.tagName))
     45
     46      return node.getAttribute(attr)
     47
     48 -def _get_attribute(node, attr):
     49      """Return an attribute by name, or None if not present."""
     50
     51      if node.hasAttribute(attr):
     52          return node.getAttribute(attr)
     53
     54      return None
     55
     56 -def _get_end_event(parser, tagName):
     57      """Check that the next event is the end of a particular tag."""
     58
     59      (event, node) = parser.next()
     60
     61      if event != pulldom.END_ELEMENT or node.tagName != tagName:
     62          raise ParseError(
     63              'Expecting %s end tag, got %s %s' % (tagName, event, node.tagName))
     64
     65 -def _is_start(event, node, tagName):
     66      """Return true if (event, node) is a start event for tagname."""
     67      return event == pulldom.START_ELEMENT and node.tagName == tagName
     68
     69 -def _is_end(event, node, tagName):
     70      """Return true if (event, node) is an end event for tagname."""
     71      return event == pulldom.END_ELEMENT and node.tagName == tagName
     72
     73  # <!-- ************************************************** -->
     74  # <!-- Root element                                       -->
     75  # <!-- ************************************************** -->
     76
     77  # <!ELEMENT CIM (MESSAGE | DECLARATION)>
     78  # <!ATTLIST CIM
     79  #       CIMVERSION CDATA #REQUIRED
     80  #       DTDVERSION CDATA #REQUIRED
     81  # >
     82
     83  # <!-- ************************************************** -->
     84  # <!-- Object declaration elements                        -->
     85  # <!-- ************************************************** -->
     86
     87  # <!ELEMENT DECLARATION (DECLGROUP | DECLGROUP.WITHNAME | DECLGROUP.WITHPATH)+>
     88  # <!ELEMENT DECLGROUP ((LOCALNAMESPACEPATH | NAMESPACEPATH)?,
     89  #                      QUALIFIER.DECLARATION*, VALUE.OBJECT*)>
     90  # <!ELEMENT DECLGROUP.WITHNAME ((LOCALNAMESPACEPATH | NAMESPACEPATH)?,
     91  #                               QUALIFIER.DECLARATION*, VALUE.NAMEDOBJECT*)>
     92  # <!ELEMENT DECLGROUP.WITHPATH (VALUE.OBJECTWITHPATH |
     93  #                               VALUE.OBJECTWITHLOCALPATH)*>
     94  # <!ELEMENT QUALIFIER.DECLARATION (SCOPE?, (VALUE | VALUE.ARRAY)?)>
     95  # <!ATTLIST QUALIFIER.DECLARATION
     96  #       %CIMName;
     97  #       %CIMType;                #REQUIRED
     98  #       ISARRAY     (true|false) #IMPLIED
     99  #       %ArraySize;
    100  #       %QualifierFlavor;
    101  # >
    102  # <!ELEMENT SCOPE EMPTY>
    103  # <!ATTLIST SCOPE
    104  #       CLASS       (true | false) "false"
    105  #       ASSOCIATION (true | false) "false"
    106  #       REFERENCE   (true | false) "false"
    107  #       PROPERTY    (true | false) "false"
    108  #       METHOD      (true | false) "false"
    109  #       PARAMETER   (true | false) "false"
    110  #       INDICATION  (true | false) "false"
    111  # >
    112
    113  # <!-- ************************************************** -->
    114  # <!-- Object Value elements                              -->
    115  # <!-- ************************************************** -->
    116
    117  # <!ELEMENT VALUE (#PCDATA)>
    118
    119 -def parse_value(parser, event, node):
    120
    121      value = ''
    122
    123      (next_event, next_node) = parser.next()
    124
    125      if next_event == pulldom.CHARACTERS:
    126
    127          value = next_node.nodeValue
    128
    129          (next_event, next_node) = parser.next()
    130
    131      if not _is_end(next_event, next_node, 'VALUE'):
    132          raise ParseError('Expecting end VALUE')
    133
    134      return value
    135
    136  # <!ELEMENT VALUE.ARRAY (VALUE*)>
    137
    138 -def parse_value_array(parser, event, node):
    139
    140      value_array = []
    141
    142      (next_event, next_node) = parser.next()
    143
    144      if _is_start(next_event, next_node, 'VALUE'):
    145
    146          value_array.append(parse_value(parser, next_event, next_node))
    147
    148          while 1:
    149
    150              (next_event, next_node) = parser.next()
    151
    152              if _is_end(next_event, next_node, 'VALUE.ARRAY'):
    153                  break
    154
    155              if _is_start(next_event, next_node, 'VALUE'):
    156                  value_array.append(parse_value(parser, next_event, next_node))
    157              else:
    158                  raise ParseError('Expecting VALUE element')
    159
    160      return value_array
    161
    162  # <!ELEMENT VALUE.REFERENCE (CLASSPATH | LOCALCLASSPATH | CLASSNAME |
    163  #                            INSTANCEPATH | LOCALINSTANCEPATH | INSTANCENAME)>
    164
    165 -def parse_value_reference(parser, event, node):
    166
    167      (next_event, next_node) = parser.next()
    168
    169      if _is_start(next_event, next_node, 'CLASSPATH'):
    170          result = parse_classpath(parser, next_event, next_node)
    171
    172      elif _is_start(next_event, next_node, 'LOCALCLASSPATH'):
    173          result = parse_localclasspath(parser, next_event, next_node)
    174
    175      elif _is_start(next_event, next_node, 'CLASSNAME'):
    176          result = parse_classname(parser, next_event, next_node)
    177
    178      elif _is_start(next_event, next_node, 'INSTANCEPATH'):
    179          result = parse_instancepath(parser, next_event, next_node)
    180
    181      elif _is_start(next_event, next_node, 'LOCALINSTANCEPATH'):
    182          result = parse_localinstancepath(parser, next_event, next_node)
    183
    184      elif _is_start(next_event, next_node, 'INSTANCENAME'):
    185          result = parse_instancename(parser, next_event, next_node)
    186
    187      else:
    188          raise ParseError('Expecting (CLASSPATH | LOCALCLASSPATH | CLASSNAME '
    189                           '| INSTANCEPATH | LOCALINSTANCEPATH | INSTANCENAME)')
    190
    191      _get_end_event(parser, 'VALUE.REFERENCE')
    192
    193      return result
    194
    195  # <!ELEMENT VALUE.REFARRAY (VALUE.REFERENCE*)>
    196  # <!ELEMENT VALUE.OBJECT (CLASS | INSTANCE)>
    197  # <!ELEMENT VALUE.NAMEDINSTANCE (INSTANCENAME, INSTANCE)>
    198  # <!ELEMENT VALUE.NAMEDOBJECT (CLASS | (INSTANCENAME, INSTANCE))>
    199  # <!ELEMENT VALUE.OBJECTWITHLOCALPATH ((LOCALCLASSPATH, CLASS) |
    200  #                                      (LOCALINSTANCEPATH, INSTANCE))>
    201  # <!ELEMENT VALUE.OBJECTWITHPATH ((CLASSPATH, CLASS) |
    202  #                                 (INSTANCEPATH, INSTANCE))>
    203  # <!ELEMENT VALUE.NULL EMPTY>
    204
    205  # <!-- ************************************************** -->
    206  # <!-- Object naming and locating elements                -->
    207  # <!-- ************************************************** -->
    208
    209  # <!ELEMENT NAMESPACEPATH (HOST, LOCALNAMESPACEPATH)>
    210
    211 -def parse_namespacepath(parser, event, node):
    212
    213      (next_event, next_node) = parser.next()
    214
    215      if not _is_start(next_event, next_node, 'HOST'):
    216          raise ParseError('Expecting HOST')
    217
    218      host = parse_host(parser, next_event, next_node)
    219
    220      (next_event, next_node) = parser.next()
    221
    222      if not _is_start(next_event, next_node, 'LOCALNAMESPACEPATH'):
    223          raise ParseError('Expecting LOCALNAMESPACEPATH')
    224
    225      namespacepath = parse_localnamespacepath(parser, next_event, next_node)
    226
    227      (next_event, next_node) = parser.next()
    228
    229      if not _is_end(next_event, next_node, 'NAMESPACEPATH'):
    230          raise ParseError('Expecting end NAMESPACEPATH')
    231
    232      return (host, namespacepath)
    233
    234  # <!ELEMENT LOCALNAMESPACEPATH (NAMESPACE+)>
    235
    236 -def parse_localnamespacepath(parser, event, node):
    237
    238      (next_event, next_node) = parser.next()
    239
    240      namespaces = []
    241
    242      if not _is_start(next_event, next_node, 'NAMESPACE'):
    243          print next_event, next_node
    244          raise ParseError('Expecting NAMESPACE')
    245
    246      namespaces.append(parse_namespace(parser, next_event, next_node))
    247
    248      while 1:
    249
    250          (next_event, next_node) = parser.next()
    251
    252          if _is_end(next_event, next_node, 'LOCALNAMESPACEPATH'):
    253              break
    254
    255          if _is_start(next_event, next_node, 'NAMESPACE'):
    256              namespaces.append(parse_namespace(parser, next_event, next_node))
    257          else:
    258              raise ParseError('Expecting NAMESPACE')
    259
    260      return string.join(namespaces, '/')
    261
    262  # <!ELEMENT HOST (#PCDATA)>
    263
    264 -def parse_host(parser, event, node):
    265
    266      host = ''
    267
    268      (next_event, next_node) = parser.next()
    269
    270      if next_event == pulldom.CHARACTERS:
    271
    272          host = next_node.nodeValue
    273
    274          (next_event, next_node) = parser.next()
    275
    276      if not _is_end(next_event, next_node, 'HOST'):
    277          raise ParseError('Expecting end HOST')
    278
    279      return host
    280
    281  # <!ELEMENT NAMESPACE EMPTY>
    282  # <!ATTLIST NAMESPACE
    283  #       %CIMName;
    284  # >
    285
    286 -def parse_namespace(parser, event, node):
    287
    288      name = _get_required_attribute(node, 'NAME')
    289
    290      (next_event, next_node) = parser.next()
    291
    292      if not _is_end(next_event, next_node, 'NAMESPACE'):
    293          raise ParseError('Expecting end NAMESPACE')
    294
    295      return name
    296
    297  # <!ELEMENT CLASSPATH (NAMESPACEPATH, CLASSNAME)>
    298
    299  # <!ELEMENT LOCALCLASSPATH (LOCALNAMESPACEPATH, CLASSNAME)>
    300
    301  # <!ELEMENT CLASSNAME EMPTY>
    302  # <!ATTLIST CLASSNAME
    303  #       %CIMName;
    304  # >
    305
    306  # <!ELEMENT INSTANCEPATH (NAMESPACEPATH, INSTANCENAME)>
    307
    308 -def parse_instancepath(parser, event, node):
    309
    310      (next_event, next_node) = parser.next()
    311
    312      if not _is_start(next_event, next_node, 'NAMESPACEPATH'):
    313          raise ParseError('Expecting NAMESPACEPATH')
    314
    315      host, namespacepath = parse_namespacepath(parser, next_event, next_node)
    316
    317      (next_event, next_node) = parser.next()
    318
    319      if not _is_start(next_event, next_node, 'INSTANCENAME'):
    320          print next_event, next_node
    321          raise ParseError('Expecting INSTANCENAME')
    322
    323      instancename = parse_instancename(parser, next_event, next_node)
    324
    325      instancename.host = host
    326      instancename.namespace = namespacepath
    327
    328      return instancename
    329
    330  # <!ELEMENT LOCALINSTANCEPATH (LOCALNAMESPACEPATH, INSTANCENAME)>
    331
    332 -def parse_localinstancepath(parser, event, node):
    333
    334      (next_event, next_node) = parser.next()
    335
    336      if not _is_start(next_event, next_node, 'LOCALNAMESPACEPATH'):
    337          raise ParseError('Expecting LOCALNAMESPACEPATH')
    338
    339      namespacepath = parse_localnamespacepath(parser, next_event, next_node)
    340
    341      (next_event, next_node) = parser.next()
    342
    343      if not _is_start(next_event, next_node, 'INSTANCENAME'):
    344          raise ParseError('Expecting INSTANCENAME')
    345
    346      instancename = parse_instancename(parser, next_event, next_node)
    347
    348      instancename.namespace = namespacepath
    349
    350      return instancename
    351
    352  # <!ELEMENT INSTANCENAME (KEYBINDING* | KEYVALUE? | VALUE.REFERENCE?)>
    353  # <!ATTLIST INSTANCENAME
    354  #       %ClassName;
    355  # >
    356
    357 -def parse_instancename(parser, event, node):
    358
    359      classname = _get_required_attribute(node, 'CLASSNAME')
    360      keybindings = []
    361
    362      (next_event, next_node) = parser.next()
    363
    364      if _is_start(next_event, next_node, 'KEYBINDING'):
    365
    366          keybindings.append(parse_keybinding(parser, next_event, next_node))
    367
    368          while 1:
    369
    370              (next_event, next_node) = parser.next()
    371
    372              if _is_end(next_event, next_node, 'INSTANCENAME'):
    373                  break
    374
    375              if _is_start(next_event, next_node, 'KEYBINDING'):
    376                  keybindings.append(
    377                      parse_keybinding(parser, next_event, next_node))
    378              else:
    379                  raise ParseError('Expecting KEYBINDING element')
    380
    381      if _is_end(next_event, next_node, 'INSTANCENAME'):
    382          pass
    383
    384      elif _is_start(next_event, next_node, 'KEYVALUE'):
    385          keybindings.append(('', parse_keyvalue(parser, next_event, next_node)))
    386
    387      elif _is_start(next_event, next_node, 'VALUE.REFERENCE'):
    388          keybindings.append(
    389              parse_value_reference(parser, next_event, next_node))
    390
    391      else:
    392          raise ParseError(
    393              'Expecting KEYBINDING* | KEYVALUE? | VALUE.REFERENCE')
    394
    395      return CIMInstanceName(classname, keybindings)
    396
    397  # <!ELEMENT OBJECTPATH (INSTANCEPATH | CLASSPATH)>
    398
    399  # <!ELEMENT KEYBINDING (KEYVALUE | VALUE.REFERENCE)>
    400  # <!ATTLIST KEYBINDING
    401  #       %CIMName;
    402  # >
    403
    404 -def parse_keybinding(parser, event, node):
    405
    406      name = _get_required_attribute(node, 'NAME')
    407
    408      (next_event, next_node) = parser.next()
    409
    410      if _is_start(next_event, next_node, 'KEYVALUE'):
    411          keyvalue = parse_keyvalue(parser, next_event, next_node)
    412          result = (name, keyvalue)
    413
    414      elif _is_start(next_event, next_node, 'VALUE.REFERENCE'):
    415          value_reference = parse_value_reference(parser, next_event, next_node)
    416          result = (name, value_reference)
    417
    418      else:
    419          raise ParseError('Expecting KEYVALUE or VALUE.REFERENCE element')
    420
    421      _get_end_event(parser, 'KEYBINDING')
    422
    423      return result
    424
    425  # <!ELEMENT KEYVALUE (#PCDATA)>
    426  # <!ATTLIST KEYVALUE
    427  #       VALUETYPE (string | boolean | numeric) "string"
    428  #       %CIMType;              #IMPLIED
    429  # >
    430
    431 -def parse_keyvalue(parser, event, node):
    432
    433      valuetype = _get_required_attribute(node, 'VALUETYPE')
    434      type = _get_attribute(node, 'TYPE')
    435
    436      (next_event, next_node) = parser.next()
    437
    438      if next_event != pulldom.CHARACTERS:
    439          raise ParseError('Expecting character data')
    440
    441      value = next_node.nodeValue
    442
    443      if valuetype == 'string':
    444          pass
    445
    446      elif valuetype == 'boolean':
    447
    448          # CIM-XML says "These values MUST be treated as
    449          # case-insensitive" (even though the XML definition
    450          # requires them to be lowercase.)
    451
    452          p = value.strip().lower()
    453
    454          if p == 'true':
    455              value = True
    456          elif p == 'false':
    457              value = False
    458          else:
    459              raise ParseError('invalid boolean value "%s"' % `p`)
    460
    461      elif valuetype == 'numeric':
    462
    463          try:
    464
    465              # XXX: Use TYPE attribute to create named CIM type.
    466              # if attrs(tt).has_key('TYPE'):
    467              #    return cim_obj.tocimobj(attrs(tt)['TYPE'], p.strip())
    468
    469              # XXX: Would like to use long() here, but that tends to cause
    470              # trouble when it's written back out as '2L'
    471
    472              value = int(value.strip(), 0)
    473
    474          except ValueError:
    475              raise ParseError(
    476                  'invalid numeric value "%s"' % value)
    477
    478      else:
    479          raise ParseError('Invalid VALUETYPE')
    480
    481      _get_end_event(parser, 'KEYVALUE')
    482
    483      return value
    484
    485  # <!-- ************************************************** -->
    486  # <!-- Object definition elements                         -->
    487  # <!-- ************************************************** -->
    488
    489  # <!ELEMENT CLASS (QUALIFIER*, (PROPERTY | PROPERTY.ARRAY |
    490  #                  PROPERTY.REFERENCE)*, METHOD*)>
    491  # <!ATTLIST CLASS
    492  #       %CIMName;
    493  #       %SuperClass;
    494  # >
    495
    496  # <!ELEMENT INSTANCE (QUALIFIER*, (PROPERTY | PROPERTY.ARRAY |
    497  #                     PROPERTY.REFERENCE)*)>
    498  # <!ATTLIST INSTANCE
    499  #       %ClassName;
    500  #       xml:lang   NMTOKEN      #IMPLIED
    501  # >
    502
    503 -def parse_instance(parser, event, node):
    504
    505      classname = _get_required_attribute(node, 'CLASSNAME')
    506
    507      properties = []
    508      qualifiers = []
    509
    510      (next_event, next_node) = parser.next()
    511
    512      if _is_start(next_event, next_node, 'QUALIFIER'):
    513
    514          qualifiers.append(parse_qualifier(parser, next_event, next_node))
    515
    516          while 1:
    517
    518              (next_event, next_node) = parser.next()
    519
    520              if _is_start(next_event, next_node, 'PROPERTY') or \
    521                 _is_start(next_event, next_node, 'PROPERTY.ARRAY') or \
    522                 _is_start(next_event, next_node, 'PROPERTY.REFERENCE') or \
    523                 _is_end(next_event, next_node, 'INSTANCE'):
    524                  break
    525
    526              if _is_start(next_event, next_node, 'QUALIFIER'):
    527                  qualifiers.append(
    528                      parse_qualifier(parser, next_event, next_node))
    529              else:
    530                  raise ParseError('Expecting QUALIFIER')
    531
    532      while 1:
    533
    534          if _is_end(next_event, next_node, 'INSTANCE'):
    535              break
    536
    537          if _is_start(next_event, next_node, 'PROPERTY'):
    538              properties.append(parse_property(parser, next_event, next_node))
    539
    540          elif _is_start(next_event, next_node, 'PROPERTY.ARRAY'):
    541              properties.append(
    542                  parse_property_array(parser, next_event, next_node))
    543
    544          elif _is_start(next_event, next_node, 'PROPERTY.REFERENCE'):
    545              properties.append(
    546                  parse_property_reference(parser, next_event, next_node))
    547          else:
    548              raise ParseError(
    549                  'Expecting (PROPERTY | PROPERTY.ARRAY | PROPERTY.REFERENCE)')
    550
    551          (next_event, next_node) = parser.next()
    552
    553      if not _is_end(next_event, next_node, 'INSTANCE'):
    554          raise ParseError('Expecting end INSTANCE')
    555
    556      return CIMInstance(
    557          classname,
    558          properties=dict([(x.name, x) for x in properties]),
    559          qualifiers=dict([(x.name, x) for x in qualifiers]))
    560
    561  # <!ELEMENT QUALIFIER ((VALUE | VALUE.ARRAY)?)>
    562  # <!ATTLIST QUALIFIER
    563  #       %CIMName;
    564  #       %CIMType;              #REQUIRED
    565  #       %Propagated;
    566  #       %QualifierFlavor;
    567  #       xml:lang   NMTOKEN     #IMPLIED
    568  # >
    569
    570 -def parse_qualifier(parser, event, node):
    571
    572      name = _get_required_attribute(node, 'NAME')
    573      type = _get_required_attribute(node, 'TYPE')
    574      propagated = _get_attribute(node, 'PROPAGATED')
    575
    576      (next_event, next_node) = parser.next()
    577
    578      if _is_end(next_event, next_node, 'QUALIFIER'):
    579          return CIMQualifier(name, None, type=type)
    580
    581      if _is_start(next_event, next_node, 'VALUE'):
    582          value = parse_value(parser, next_event, next_node)
    583      elif _is_start(next_event, next_node, 'VALUE.ARRAY'):
    584          value = parse_value_array(parser, next_event, next_node)
    585      else:
    586          raise ParseError('Expecting (VALUE | VALUE.ARRAY)')
    587
    588      result = CIMQualifier(name, cim_obj.tocimobj(type, value))
    589
    590      _get_end_event(parser, 'QUALIFIER')
    591
    592      return result
    593
    594  # <!ELEMENT PROPERTY (QUALIFIER*, VALUE?)>
    595  # <!ATTLIST PROPERTY
    596  #       %CIMName;
    597  #       %ClassOrigin;
    598  #       %Propagated;
    599  #       %CIMType;              #REQUIRED
    600  #       xml:lang   NMTOKEN     #IMPLIED
    601  # >
    602
    603 -def parse_property(parser, event, node):
    604
    605      name = _get_required_attribute(node, 'NAME')
    606      type = _get_required_attribute(node, 'TYPE')
    607
    608      class_origin = _get_attribute(node, 'CLASSORIGIN')
    609      propagated = _get_attribute(node, 'PROPAGATED')
    610
    611      qualifiers = []
    612      value = None
    613
    614      (next_event, next_node) = parser.next()
    615
    616      if _is_start(next_event, next_node, 'QUALIFIER'):
    617
    618          qualifiers.append(parse_qualifier(parser, next_event, next_node))
    619
    620          while 1:
    621
    622              (next_event, next_node) = parser.next()
    623
    624              if _is_start(next_event, next_node, 'VALUE'):
    625                  break
    626
    627              if _is_start(next_event, next_node, 'QUALIFIER'):
    628                  qualifiers.append(
    629                      parse_qualifier(parser, next_event, next_node))
    630              else:
    631                  raise ParseError('Expecting QUALIFIER')
    632
    633      if _is_start(next_event, next_node, 'VALUE'):
    634
    635          value = parse_value(parser, next_event, next_node)
    636          (next_event, next_node) = parser.next()
    637
    638      if not _is_end(next_event, next_node, 'PROPERTY'):
    639          raise ParseError('Expecting end PROPERTY')
    640
    641      return CIMProperty(
    642          name,
    643          cim_obj.tocimobj(type, value),
    644          type=type,
    645          class_origin=class_origin,
    646          propagated=propagated,
    647          qualifiers=dict([(x.name, x) for x in qualifiers]))
    648
    649  # <!ELEMENT PROPERTY.ARRAY (QUALIFIER*, VALUE.ARRAY?)>
    650  # <!ATTLIST PROPERTY.ARRAY
    651  #       %CIMName;
    652  #       %CIMType;              #REQUIRED
    653  #       %ArraySize;
    654  #       %ClassOrigin;
    655  #       %Propagated;
    656  #       xml:lang   NMTOKEN     #IMPLIED
    657  # >
    658
    659 -def parse_property_array(parser, event, node):
    660
    661      name = _get_required_attribute(node, 'NAME')
    662      type = _get_required_attribute(node, 'TYPE')
    663
    664      array_size = _get_attribute(node, 'ARRAYSIZE')
    665      class_origin = _get_attribute(node, 'CLASSORIGIN')
    666      propagated = _get_attribute(node, 'PROPAGATED')
    667
    668      qualifiers = []
    669      value = None
    670
    671      (next_event, next_node) = parser.next()
    672
    673      if _is_start(next_event, next_node, 'QUALIFIER'):
    674
    675          qualifiers.append(parse_qualifier(parser, next_event, next_node))
    676
    677          while 1:
    678
    679              (next_event, next_node) = parser.next()
    680
    681              if _is_start(next_event, next_node, 'VALUE.ARRAY'):
    682                  break
    683
    684              if _is_start(next_event, next_node, 'QUALIFIER'):
    685                  qualifiers.append(
    686                      parse_qualifier(parser, next_event, next_node))
    687              else:
    688                  raise ParseError('Expecting QUALIFIER')
    689
    690      if _is_start(next_event, next_node, 'VALUE.ARRAY'):
    691
    692          value = parse_value_array(parser, next_event, next_node)
    693          (next_event, next_node) = parser.next()
    694
    695      if not _is_end(next_event, next_node, 'PROPERTY.ARRAY'):
    696          raise ParseError('Expecting end PROPERTY.ARRAY')
    697
    698      return CIMProperty(
    699          name,
    700          cim_obj.tocimobj(type, value),
    701          type=type,
    702          class_origin=class_origin,
    703          propagated=propagated,
    704          is_array=True,
    705          qualifiers=dict([(x.name, x) for x in qualifiers]))
    706
    707  # <!ELEMENT PROPERTY.REFERENCE (QUALIFIER*, (VALUE.REFERENCE)?)>
    708  # <!ATTLIST PROPERTY.REFERENCE
    709  #       %CIMName;
    710  #       %ReferenceClass;
    711  #       %ClassOrigin;
    712  #       %Propagated;
    713  # >
    714
    715 -def parse_property_reference(parser, event, node):
    716
    717      name = _get_required_attribute(node, 'NAME')
    718
    719      class_origin = _get_attribute(node, 'CLASSORIGIN')
    720      propagated = _get_attribute(node, 'PROPAGATED')
    721
    722      qualifiers = []
    723      value = None
    724
    725      (next_event, next_node) = parser.next()
    726
    727      if _is_start(next_event, next_node, 'QUALIFIER'):
    728
    729          qualifiers.append(parse_qualifier(parser, next_event, next_node))
    730
    731          while 1:
    732
    733              (next_event, next_node) = parser.next()
    734
    735              if _is_start(next_event, next_node, 'VALUE.REFERENCE'):
    736                  break
    737
    738              if _is_start(next_event, next_node, 'QUALIFIER'):
    739                  qualifiers.append(
    740                      parse_qualifier(parser, next_event, next_node))
    741
    742              else:
    743                  raise ParseError('Expecting QUALIFIER')
    744
    745      if _is_start(next_event, next_node, 'VALUE.REFERENCE'):
    746
    747          value = parse_value_reference(parser, next_event, next_node)
    748          (next_event, next_node) = parser.next()
    749
    750      if not _is_end(next_event, next_node, 'PROPERTY.REFERENCE'):
    751          raise ParseError('Expecting end PROPERTY.REFERENCE')
    752
    753      return CIMProperty(
    754          name,
    755          value,
    756          class_origin=class_origin,
    757          propagated=propagated,
    758          type='reference',
    759          qualifiers=dict([(x.name, x) for x in qualifiers]))
    760
    761  # <!ELEMENT METHOD (QUALIFIER*, (PARAMETER | PARAMETER.REFERENCE |
    762  #                   PARAMETER.ARRAY | PARAMETER.REFARRAY)*)>
    763  # <!ATTLIST METHOD
    764  #       %CIMName;
    765  #       %CIMType;              #IMPLIED
    766  #       %ClassOrigin;
    767  #       %Propagated;>
    768
    769  # <!ELEMENT PARAMETER (QUALIFIER*)>
    770  # <!ATTLIST PARAMETER
    771  #       %CIMName;
    772  #       %CIMType;              #REQUIRED>
    773
    774  # <!ELEMENT PARAMETER.REFERENCE (QUALIFIER*)>
    775  # <!ATTLIST PARAMETER.REFERENCE
    776  #       %CIMName;
    777  #       %ReferenceClass;
    778  # >
    779
    780  # <!ELEMENT PARAMETER.ARRAY (QUALIFIER*)>
    781  # <!ATTLIST PARAMETER.ARRAY
    782  #       %CIMName;
    783  #       %CIMType;              #REQUIRED
    784  #       %ArraySize;>
    785
    786  # <!ELEMENT PARAMETER.REFARRAY (QUALIFIER*)>
    787  # <!ATTLIST PARAMETER.REFARRAY
    788  #       %CIMName;
    789  #       %ReferenceClass;
    790  #       %ArraySize;
    791  # >
    792
    793  # <!ELEMENT TABLECELL.DECLARATION EMPTY>
    794  # <!ATTLIST TABLECELL.DECLARATION
    795  #       %CIMName;
    796  #       %CIMType;                               #REQUIRED
    797  #       ISARRAY         (true|false) "false"
    798  #       %ArraySize;
    799  #       CELLPOS         CDATA                   #REQUIRED
    800  #       SORTPOS         CDATA                   #IMPLIED
    801  #       SORTDIR         (ASC|DESC)              #IMPLIED
    802  # >
    803
    804  # <!ELEMENT TABLECELL.REFERENCE EMPTY>
    805  # <!ATTLIST TABLECELL.REFERENCE
    806  #       %CIMName;
    807  #       %ReferenceClass;
    808  #       ISARRAY         (true|false) "false"
    809  #       %ArraySize;
    810  #       CELLPOS         CDATA                   #REQUIRED
    811  #       SORTPOS         CDATA                   #IMPLIED
    812  #       SORTDIR         (ASC|DESC)              #IMPLIED
    813  # >
    814
    815  # <!ELEMENT TABLEROW.DECLARATION (TABLECELL.DECLARATION | TABLECELL.REFERENCE)*>
    816
    817  # <!ELEMENT TABLE (TABLEROW.DECLARATION,(TABLEROW)*)>
    818
    819  # <!ELEMENT TABLEROW (VALUE | VALUE.ARRAY | VALUE.REFERENCE | VALUE.REFARRAY |
    820  #                     VALUE.NULL)*>
    821
    822  # <!-- ************************************************** -->
    823  # <!-- Message elements                                   -->
    824  # <!-- ************************************************** -->
    825
    826  # <!ELEMENT MESSAGE (SIMPLEREQ | MULTIREQ | SIMPLERSP | MULTIRSP |
    827  #                    SIMPLEEXPREQ | MULTIEXPREQ | SIMPLEEXPRSP | MULTIEXPRSP)>
    828  # <!ATTLIST MESSAGE
    829  #       ID              CDATA #REQUIRED
    830  #       PROTOCOLVERSION CDATA #REQUIRED
    831  # >
    832
    833  # <!ELEMENT MULTIREQ (SIMPLEREQ, SIMPLEREQ+)>
    834
    835  # <!ELEMENT MULTIEXPREQ (SIMPLEEXPREQ, SIMPLEEXPREQ+)>
    836
    837  # <!ELEMENT SIMPLEREQ (IMETHODCALL | METHODCALL)>
    838
    839  # <!ELEMENT SIMPLEEXPREQ (EXPMETHODCALL)>
    840
    841  # <!ELEMENT IMETHODCALL (LOCALNAMESPACEPATH, IPARAMVALUE*,
    842  #                        RESPONSEDESTINATION?)>
    843  # <!ATTLIST IMETHODCALL
    844  #       %CIMName;
    845  # >
    846
    847  # <!ELEMENT METHODCALL ((LOCALINSTANCEPATH | LOCALCLASSPATH), PARAMVALUE*,
    848  #                       RESPONSEDESTINATION?)>
    849  # <!ATTLIST METHODCALL
    850  #       %CIMName;
    851  # >
    852
    853  # <!ELEMENT EXPMETHODCALL (EXPPARAMVALUE*)>
    854  # <!ATTLIST EXPMETHODCALL
    855  #       %CIMName;
    856  # >
    857
    858  # <!ELEMENT PARAMVALUE (VALUE | VALUE.REFERENCE | VALUE.ARRAY |
    859  #                       VALUE.REFARRAY)?>
    860  # <!ATTLIST PARAMVALUE
    861  #       %CIMName;
    862  #       %ParamType;  #IMPLIED
    863  # >
    864
    865  # <!ELEMENT IPARAMVALUE (VALUE | VALUE.ARRAY | VALUE.REFERENCE | INSTANCENAME |
    866  #                        CLASSNAME | QUALIFIER.DECLARATION | CLASS | INSTANCE |
    867  #                        VALUE.NAMEDINSTANCE)?>
    868  # <!ATTLIST IPARAMVALUE
    869  #       %CIMName;
    870  # >
    871
    872  # <!ELEMENT EXPPARAMVALUE (INSTANCE? | VALUE? | METHODRESPONSE? |
    873  #                          IMETHODRESPONSE?)>
    874  # <!ATTLIST EXPPARAMVALUE
    875  #       %CIMName;
    876  # >
    877
    878  # <!ELEMENT MULTIRSP (SIMPLERSP, SIMPLERSP+)>
    879
    880  # <!ELEMENT MULTIEXPRSP (SIMPLEEXPRSP, SIMPLEEXPRSP+)>
    881
    882  # <!ELEMENT SIMPLERSP (METHODRESPONSE | IMETHODRESPONSE | SIMPLEREQACK)>
    883
    884  # <!ELEMENT SIMPLEEXPRSP (EXPMETHODRESPONSE)>
    885
    886  # <!ELEMENT METHODRESPONSE (ERROR | (RETURNVALUE?, PARAMVALUE*))>
    887  # <!ATTLIST METHODRESPONSE
    888  #       %CIMName;
    889  # >
    890
    891  # <!ELEMENT EXPMETHODRESPONSE (ERROR | IRETURNVALUE?)>
    892  # <!ATTLIST EXPMETHODRESPONSE
    893  #       %CIMName;
    894  # >
    895
    896  # <!ELEMENT IMETHODRESPONSE (ERROR | IRETURNVALUE?)>
    897  # <!ATTLIST IMETHODRESPONSE
    898  #       %CIMName;
    899  # >
    900
    901  # <!ELEMENT ERROR (INSTANCE*)>
    902  # <!ATTLIST ERROR
    903  #       CODE        CDATA #REQUIRED
    904  #       DESCRIPTION CDATA #IMPLIED
    905  # >
    906
    907  # <!ELEMENT RETURNVALUE (VALUE | VALUE.REFERENCE)>
    908  # <!ATTLIST RETURNVALUE
    909  #       %ParamType;       #IMPLIED
    910  # >
    911
    912  # <!ELEMENT IRETURNVALUE (CLASSNAME* | INSTANCENAME* | VALUE* |
    913  #                         VALUE.OBJECTWITHPATH* | VALUE.OBJECTWITHLOCALPATH* |
    914  #                         VALUE.OBJECT* | OBJECTPATH* | QUALIFIER.DECLARATION* |
    915  #                         VALUE.ARRAY? | VALUE.REFERENCE? | CLASS* | INSTANCE* |
    916  #                         VALUE.NAMEDINSTANCE*)>
    917
    918  # <!ELEMENT RESPONSEDESTINATION (INSTANCE)>
    919
    920  # <!ELEMENT SIMPLEREQACK (ERROR?)>
    921  # <!ATTLIST SIMPLEREQACK
    922  #       INSTANCEID CDATA     #REQUIRED
    923  # >
    924
    925 -def make_parser(stream_or_string):
    926      """Create a xml.dom.pulldom parser."""
    927
    928      if type(stream_or_string) == str or type(stream_or_string) == unicode:
    929
    930          # XXX: the pulldom.parseString() function doesn't seem to
    931          # like operating on unicode strings!
    932
    933          return pulldom.parseString(str(stream_or_string))
    934
    935      else:
    936
    937          return pulldom.parse(stream_or_string)
    938
    939 -def parse_any(stream_or_string):
    940      """Parse any XML string or stream."""
    941
    942      parser = make_parser(stream_or_string)
    943
    944      (event, node) = parser.next()
    945
    946      if event != pulldom.START_DOCUMENT:
    947          raise ParseError('Expecting document start')
    948
    949      (event, node) = parser.next()
    950
    951      if event != pulldom.START_ELEMENT:
    952          raise ParseError('Expecting element start')
    953
    954      fn_name = 'parse_%s' % node.tagName.lower().replace('.', '_')
    955      fn = globals().get(fn_name)
    956      if fn is None:
    957          raise ParseError('No parser for element %s' % node.tagName)
    958
    959      return fn(parser, event, node)
    960
    961  # Test harness
    962
    963  if __name__ == '__main__':
    964      import sys
    965      print parse_any(sys.stdin)
    966