rubywbem 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1181 @@
1
+ #
2
+ # Copyright 2006, Red Hat, Inc
3
+ # Scott Seago <sseago@redhat.com>
4
+ #
5
+ # derived from pywbem, written by Tim Potter <tpot@hp.com>, Martin Pool <mbp@hp.com>
6
+ #
7
+ # This program is free software; you can redistribute it and/or modify
8
+ # it under the terms of the GNU General Public License as published by
9
+ # the Free Software Foundation; either version 2 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, write to the Free Software
14
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15
+ #
16
+
17
+ # '''Tuple parser for the XML schema representing CIM messages.
18
+
19
+ # This framework is meant to add some value to the tuple-tree
20
+ # representation of CIM in XML by having the following properties:
21
+
22
+ # - Silently ignoring whitespace text elements
23
+
24
+ # - Conversion from tuple-tree representation into a python dictionary
25
+ # which can then be accessed in a readable fashion.
26
+
27
+ # - Validation of the XML elements and attributes without having to
28
+ # use the DTD file or any external tools.
29
+
30
+ # '''
31
+
32
+ # Implementation: this works by a recursive descent down the CIM XML
33
+ # tupletree. As we walk down, we produce cim_obj and cim_type
34
+ # objects representing the CIM message in digested form.
35
+
36
+ # For each XML node type FOO there is one function parse_foo, which
37
+ # returns the digested form by examining a tuple tree rooted at FOO.
38
+
39
+ # The resulting objects are constrained to the shape of the CIM XML
40
+ # tree: if one node in XML contains another, then the corresponding
41
+ # CIM object will contain the second. However, there can be local
42
+ # transformations at each node: some levels are ommitted, some are
43
+ # transformed into lists or hashes.
44
+
45
+ # We try to validate that the tree is well-formed too. The validation
46
+ # is more strict than the DTD, but it is forgiving of implementation
47
+ # quirks and bugs in Pegasus.
48
+
49
+ # Bear in mind in the parse functions that each tupletree tuple is
50
+ # structured as
51
+
52
+ # tt[0]: name string == name(tt)
53
+ # tt[1]: hash of attributes == attrs(tt)
54
+ # tt[2]: sequence of children == kids(tt)
55
+
56
+ # At the moment this layer is a little inconsistent: in some places it
57
+ # returns tupletrees, and in others Python objects. It may be better
58
+ # to hide the tupletree/XML representation from higher level code.
59
+
60
+
61
+ # TODO: Maybe take a DTD fragment like "(DECLGROUP |
62
+ # DECLGROUP.WITHNAME | DECLGROUP.WITHPATH)*", parse that and check it
63
+ # directly.
64
+
65
+ # TODO: Syntax-check some attributes with defined formats, such as NAME
66
+
67
+ # TODO: Implement qualifiers by making subclasses of CIM types with a
68
+ # .qualifiers property.
69
+
70
+ require "wbem/cim_obj"
71
+ require "date"
72
+
73
+ module WBEM
74
+
75
+ class ParseError < Exception
76
+ #"""This exception is raised when there is a validation error detected
77
+ #by the parser."""
78
+ end
79
+
80
+ def WBEM.filter_tuples(l)
81
+ # """Return only the tuples in a list.
82
+
83
+ # In a tupletree, tuples correspond to XML elements. Useful for
84
+ # stripping out whitespace data in a child list."""
85
+ if l.nil?
86
+ []
87
+ else
88
+ l.find_all { |x| x.is_a? Array }
89
+ end
90
+ end
91
+
92
+ def WBEM.pcdata(tt)
93
+ # """Return the concatenated character data within a tt.
94
+
95
+ # The tt must not have non-character children."""
96
+ tt[2].each do |x|
97
+ unless x.is_a? String
98
+ raise ParseError, "unexpected node #{x} under #{tt}"
99
+ end
100
+ end
101
+ tt[2].join
102
+ end
103
+
104
+ def WBEM.name(tt)
105
+ tt[0]
106
+ end
107
+
108
+ def WBEM.attrs(tt)
109
+ tt[1]
110
+ end
111
+
112
+ def WBEM.kids(tt)
113
+ WBEM.filter_tuples(tt[2])
114
+ end
115
+
116
+ def WBEM.check_node(tt, nodename, required_attrs = [], optional_attrs = [],
117
+ allowed_children = nil,
118
+ allow_pcdata = false)
119
+ # """Check static local constraints on a single node.
120
+
121
+ # The node must have the given name. The required attrs must be
122
+ # present, and the optional attrs may be.
123
+
124
+ # If allowed_children is not nil, the node may have children of the
125
+ # given types. It can be [] for nodes that may not have any
126
+ # children. If it's nil, it is assumed the children are validated
127
+ # in some other way.
128
+
129
+ # If allow_pcdata is true, then non-whitespace text children are allowed.
130
+ # (Whitespace text nodes are always allowed.)
131
+ # """
132
+
133
+ unless WBEM.name(tt) == nodename
134
+ raise ParseError, "expected node type #{nodename}, not #{WBEM.name(tt)} \n #{tt}"
135
+ end
136
+
137
+ # Check we have all the required attributes, and no unexpected ones
138
+ tt_attrs = {}
139
+ tt_attrs = WBEM.attrs(tt).clone unless WBEM.attrs(tt).nil?
140
+
141
+ required_attrs.each do |attr|
142
+ unless tt_attrs.has_key?(attr)
143
+ raise ParseError, "expected #{attr} attribute on #{WBEM.name(tt)} node, but only have #{WBEM.attrs(tt).keys()}"
144
+ end
145
+ tt_attrs.delete(attr)
146
+ end
147
+
148
+ optional_attrs.each { |attr| tt_attrs.delete(attr) }
149
+
150
+ unless tt_attrs.empty?
151
+ raise ParseError, "invalid extra attributes #{tt_attrs.keys()}"
152
+ end
153
+
154
+ unless allowed_children.nil?
155
+ WBEM.kids(tt).each do |c|
156
+ unless allowed_children.include?(WBEM.name(c))
157
+ raise ParseError, "unexpected node #{WBEM.name(c)} under #{WBEM.name(tt)}; wanted #{allowed_children}"
158
+ end
159
+ end
160
+ end
161
+
162
+ unless allow_pcdata
163
+ tt[2].each do |c|
164
+ if (c.is_a? String and c.delete(" \t\n").length > 0)
165
+ raise ParseError, "unexpected non-blank pcdata node #{c} under #{WBEM.name(tt)}"
166
+ end
167
+ end
168
+ end
169
+ end
170
+
171
+ def WBEM.one_child(tt, acceptable)
172
+ # """Parse children of a node with exactly one child node.
173
+
174
+ # PCData is ignored.
175
+ # """
176
+ k = WBEM.kids(tt)
177
+
178
+ unless k.length == 1
179
+ raise ParseError, "expecting just one #{acceptable}, got #{k.each {|t| t[0] }}"
180
+ end
181
+
182
+ child = k[0]
183
+
184
+ unless acceptable.include?(WBEM.name(child))
185
+ raise ParseError, "expecting one of #{acceptable}, got #{WBEM.name(child)} under #{WBEM.name(tt)}"
186
+ end
187
+
188
+ return WBEM.parse_any(child)
189
+ end
190
+
191
+ def WBEM.optional_child(tt, allowed)
192
+ # """Parse exactly zero or one of a list of elements from the
193
+ # child nodes."""
194
+ k = WBEM.kids(tt)
195
+
196
+ if k.length > 1
197
+ raise ParseError, "expecting zero or one of #{allowed} under #{tt}"
198
+ elsif k.length == 1
199
+ return WBEM.one_child(tt, allowed)
200
+ else
201
+ return nil
202
+ end
203
+ end
204
+
205
+ def WBEM.list_of_various(tt, acceptable)
206
+ # """Parse zero or more of a list of elements from the child nodes.
207
+
208
+ # Each element of the list can be any type from the list of acceptable
209
+ # nodes."""
210
+
211
+ r = []
212
+
213
+ WBEM.kids(tt).each do |child|
214
+ unless acceptable.include?(WBEM.name(child))
215
+ raise ParseError, "expected one of #{acceptable} under #{WBEM.name(tt)}, got #{WBEM.name(child)}"
216
+ end
217
+ r << WBEM.parse_any(child)
218
+ end
219
+ return r
220
+ end
221
+
222
+ def WBEM.list_of_matching(tt, matched)
223
+ # """Parse only the children of particular types under tt.
224
+
225
+ # Other children are ignored rather than giving an error."""
226
+
227
+ r = []
228
+
229
+ WBEM.kids(tt).each do |child|
230
+ r << WBEM.parse_any(child) if matched.include?(WBEM.name(child))
231
+ end
232
+ return r
233
+ end
234
+
235
+ def WBEM.list_of_same(tt, acceptable)
236
+ # """Parse a list of elements from child nodes.
237
+
238
+ # The children can be any of the listed acceptable types, but they
239
+ # must all be the same.
240
+ # """
241
+
242
+ unless (k = WBEM.kids(tt))
243
+ return [] # empty list, consistent with list_of_various
244
+ end
245
+
246
+ w = WBEM.name(k[0])
247
+ unless acceptable.include?(w)
248
+ raise ParseError, "expected one of #{acceptable} under #{WBEM.name(tt)}, got #{WBEM.name(child)}"
249
+ end
250
+ r = []
251
+ k.each do |child|
252
+ unless WBEM.name(child) == w
253
+ raise ParseError, "expected list of #{w} under #{WBEM.name(child)}, but found #{WBEM.name(tt)}"
254
+ end
255
+ r << WBEM.parse_any(child)
256
+ end
257
+ return r
258
+ end
259
+
260
+ def WBEM.notimplemented(tt)
261
+ raise ParseError, "parser for #{WBEM.name(tt)} not implemented"
262
+ end
263
+ #
264
+ # Root element
265
+ #
266
+
267
+ def WBEM.parse_cim(tt)
268
+ # """
269
+ # <!ELEMENT CIM (MESSAGE | DECLARATION)>
270
+ # <!ATTLIST CIM
271
+ # CIMVERSION CDATA #REQUIRED
272
+ # DTDVERSION CDATA #REQUIRED>
273
+ # """
274
+
275
+ WBEM.check_node(tt, "CIM", ["CIMVERSION", "DTDVERSION"])
276
+
277
+ unless WBEM.attrs(tt)["CIMVERSION"] == "2.0"
278
+ raise ParseError, "CIMVERSION is #{WBEM.attrs(tt)[CIMVERSION]}, expected 2.0"
279
+ end
280
+ child = WBEM.one_child(tt, ["MESSAGE", "DECLARATION"])
281
+ return [WBEM.name(tt), WBEM.attrs(tt), child]
282
+ end
283
+
284
+ #
285
+ # Object value elements
286
+ #
287
+
288
+ def WBEM.parse_value(tt)
289
+ # '''Return VALUE contents as a string'''
290
+ ## <!ELEMENT VALUE (#PCDATA)>
291
+ WBEM.check_node(tt, "VALUE", [], [], [], true)
292
+ return WBEM.pcdata(tt)
293
+ end
294
+
295
+ def WBEM.parse_value_array(tt)
296
+ #"""Return list of strings."""
297
+ ## <!ELEMENT VALUE.ARRAY (VALUE*)>
298
+ WBEM.check_node(tt, "VALUE.ARRAY", [], [], ["VALUE"])
299
+ return WBEM.list_of_same(tt, ["VALUE"])
300
+ end
301
+
302
+ def WBEM.parse_value_reference(tt)
303
+ # """
304
+ # <!ELEMENT VALUE.REFERENCE (CLASSPATH | LOCALCLASSPATH | CLASSNAME |
305
+ # INSTANCEPATH | LOCALINSTANCEPATH |
306
+ # INSTANCENAME)>
307
+ # """
308
+
309
+ WBEM.check_node(tt, "VALUE.REFERENCE", [])
310
+
311
+ child = WBEM.one_child(tt,
312
+ ["CLASSPATH", "LOCALCLASSPATH", "CLASSNAME",
313
+ "INSTANCEPATH", "LOCALINSTANCEPATH",
314
+ "INSTANCENAME"])
315
+
316
+ # The VALUE.REFERENCE wrapper element is discarded
317
+ return child
318
+ end
319
+
320
+ def WBEM.parse_value_refarray(tt)
321
+ # """
322
+ # <!ELEMENT VALUE.REFARRAY (VALUE.REFERENCE*)>
323
+ # """
324
+
325
+ WBEM.check_node(tt, "VALUE.REFARRAY")
326
+ children = WBEM.list_of_various(tt, ["VALUE.REFERENCE"])
327
+ return [WBEM.name(tt), WBEM.attrs(tt), children]
328
+ end
329
+
330
+ def WBEM.parse_value_object(tt)
331
+ # """
332
+ # <!ELEMENT VALUE.OBJECT (CLASS | INSTANCE)>
333
+ # """
334
+
335
+ WBEM.check_node(tt, "VALUE.OBJECT")
336
+ child = WBEM.one_child(tt, ["CLASS", "INSTANCE"])
337
+ return [WBEM.name(tt), WBEM.attrs(tt), child]
338
+ end
339
+
340
+ def WBEM.parse_value_namedinstance(tt)
341
+ # """
342
+ # <!ELEMENT VALUE.NAMEDINSTANCE (INSTANCENAME, INSTANCE)>
343
+ # """
344
+
345
+ WBEM.check_node(tt, "VALUE.NAMEDINSTANCE")
346
+ k = WBEM.kids(tt)
347
+ unless k.length == 2
348
+ raise ParseError, "expecting (INSTANCENAME, INSTANCE), got #{k}"
349
+ end
350
+ instancename = WBEM.parse_instancename(k[0])
351
+ instance = WBEM.parse_instance(k[1])
352
+ instance.path = instancename
353
+ return instance
354
+ end
355
+
356
+ def WBEM.parse_value_namedobject(tt)
357
+ # """
358
+ # <!ELEMENT VALUE.NAMEDOBJECT (CLASS | (INSTANCENAME, INSTANCE))>
359
+ # """
360
+
361
+ WBEM.check_node(tt, "VALUE.NAMEDOBJECT")
362
+ k = WBEM.kids(tt)
363
+ if k.length == 1
364
+ object = WBEM.parse_class(k[0])
365
+ elsif k.length == 2
366
+ path = WBEM.parse_instancename(k[0])
367
+ object = WBEM.parse_instance(k[1])
368
+ object.path = path
369
+ else
370
+ raise ParseError, "Expecting one or two elements, got #{k}"
371
+ end
372
+ return [WBEM.name(tt), WBEM.attrs(tt), object]
373
+ end
374
+
375
+ def WBEM.parse_value_objectwithlocalpath(tt)
376
+ # """
377
+ # <!ELEMENT VALUE.OBJECTWITHLOCALPATH ((LOCALCLASSPATH, CLASS) |
378
+ # (LOCALINSTANCEPATH, INSTANCE))>
379
+ # """
380
+
381
+ WBEM.check_node(tt, "VALUE.OBJECTWITHLOCALPATH")
382
+ k = WBEM.kids(tt)
383
+ unless k.length == 2
384
+ raise ParseError, "Expecting two elements, got #{k.length}"
385
+ end
386
+ if k[0][0] == "LOCALCLASSPATH"
387
+ object = [WBEM.parse_localclasspath(k[0]),
388
+ WBEM.parse_class(k[1])]
389
+ else
390
+ path = WBEM.parse_localinstancepath(k[0])
391
+ object = WBEM.parse_instance(k[1])
392
+ object.path = path
393
+ end
394
+ return [WBEM.name(tt), WBEM.attrs(tt), object]
395
+ end
396
+
397
+ def WBEM.parse_value_objectwithpath(tt)
398
+ # """
399
+ # <!ELEMENT VALUE.OBJECTWITHPATH ((CLASSPATH, CLASS) |
400
+ # (INSTANCEPATH, INSTANCE))>
401
+ # """
402
+
403
+ WBEM.check_node(tt, "VALUE.OBJECTWITHPATH")
404
+ k = WBEM.kids(tt)
405
+ unless k.length == 2
406
+ raise ParseError, "Expecting two elements, got #{k.length}"
407
+ end
408
+
409
+ if WBEM.name(k[0]) == "CLASSPATH"
410
+ object = [WBEM.parse_classpath(k[0]),
411
+ WBEM.parse_class(k[1])]
412
+ else
413
+ path = WBEM.parse_instancepath(k[0])
414
+ object = WBEM.parse_instance(k[1])
415
+ object.path = path
416
+ end
417
+ return [WBEM.name(tt), WBEM.attrs(tt), object]
418
+ end
419
+
420
+ #
421
+ # Object naming and locating elements
422
+ #
423
+
424
+ def WBEM.parse_namespacepath(tt)
425
+ # """
426
+ # <!ELEMENT NAMESPACEPATH (HOST, LOCALNAMESPACEPATH)>
427
+ # """
428
+
429
+ WBEM.check_node(tt, "NAMESPACEPATH")
430
+ unless ((k = WBEM.kids(tt)).length == 2)
431
+ raise ParseError, "Expecting (HOST, LOCALNAMESPACEPATH) got #{WBEM.kids(tt).keys()}"
432
+ end
433
+
434
+ host = WBEM.parse_host(k[0])
435
+ localnspath = WBEM.parse_localnamespacepath(k[1])
436
+ return CIMNamespacePath.new(host, localnspath)
437
+ end
438
+
439
+ def WBEM.parse_localnamespacepath(tt)
440
+ # """
441
+ # <!ELEMENT LOCALNAMESPACEPATH (NAMESPACE+)>
442
+ # """
443
+ WBEM.check_node(tt, "LOCALNAMESPACEPATH", [], [], ["NAMESPACE"])
444
+ if WBEM.kids(tt).length == 0
445
+ raise ParseError, "Expecting one or more of NAMESPACE, got nothing"
446
+ end
447
+ WBEM.list_of_various(tt, ["NAMESPACE"]).join("/")
448
+ end
449
+
450
+ def WBEM.parse_host(tt)
451
+ # """
452
+ # <!ELEMENT HOST (#PCDATA)>
453
+ # """
454
+ WBEM.check_node(tt, "HOST", [], [], nil , true)
455
+ return WBEM.pcdata(tt)
456
+ end
457
+
458
+ def WBEM.parse_namespace(tt)
459
+ # """
460
+ # <!ELEMENT NAMESPACE EMPTY>
461
+ # <!ATTLIST NAMESPACE
462
+ # %CIMName;>
463
+ # """
464
+
465
+ WBEM.check_node(tt, "NAMESPACE", ["NAME"], [], [])
466
+ return WBEM.attrs(tt)["NAME"]
467
+ end
468
+
469
+ def WBEM.parse_classpath(tt)
470
+ # """
471
+ # <!ELEMENT CLASSPATH (NAMESPACEPATH, CLASSNAME)>
472
+ # """
473
+ WBEM.check_node(tt, "CLASSPATH")
474
+ unless ((k = WBEM.kids(tt)).length == 2)
475
+ raise ParseError, "Expecting (NAMESPACEPATH, CLASSNAME) got #{k.keys()}"
476
+ end
477
+ nspath = WBEM.parse_namespacepath(k[0])
478
+ classname = WBEM.parse_classname(k[1])
479
+ return CIMClassPath.new(nspath.host, nspath.localnamespacepath,
480
+ classname.classname)
481
+ end
482
+
483
+ def WBEM.parse_localclasspath(tt)
484
+ # """
485
+ # <!ELEMENT LOCALCLASSPATH (LOCALNAMESPACEPATH, CLASSNAME)>
486
+ # """
487
+ WBEM.check_node(tt, "LOCALCLASSPATH")
488
+ unless ((k = WBEM.kids(tt)).length == 2)
489
+ raise ParseError, "Expecting (LOCALNAMESPACEPATH, CLASSNAME) got #{k.keys()}"
490
+ end
491
+ localnspath = WBEM.parse_localnamespacepath(k[0])
492
+ classname = WBEM.parse_classname(k[1])
493
+ return CIMLocalClassPath.new(localnspath, classname.classname)
494
+ end
495
+
496
+ def WBEM.parse_classname(tt)
497
+ # """
498
+ # <!ELEMENT CLASSNAME EMPTY>
499
+ # <!ATTLIST CLASSNAME
500
+ # %CIMName;>
501
+ # """
502
+ WBEM.check_node(tt, "CLASSNAME", ["NAME"], [], [])
503
+ return CIMClassName.new(WBEM.attrs(tt)["NAME"])
504
+ end
505
+
506
+ def WBEM.parse_instancepath(tt)
507
+ # """
508
+ # <!ELEMENT INSTANCEPATH (NAMESPACEPATH, INSTANCENAME)>
509
+ # """
510
+
511
+ WBEM.check_node(tt, "INSTANCEPATH")
512
+
513
+ unless ((k = WBEM.kids(tt)).length == 2)
514
+ raise ParseError, "Expecting (NAMESPACEPATH, INSTANCENAME) got #{k}"
515
+ end
516
+ nspath = WBEM.parse_namespacepath(k[0])
517
+ instancename = WBEM.parse_instancename(k[1])
518
+ instancename.host = nspath.host
519
+ instancename.namespace = nspath.localnamespacepath
520
+
521
+ return instancename
522
+ end
523
+
524
+ def WBEM.parse_localinstancepath(tt)
525
+ # """
526
+ # <!ELEMENT LOCALINSTANCEPATH (LOCALNAMESPACEPATH, INSTANCENAME)>
527
+ # """
528
+
529
+ WBEM.check_node(tt, "LOCALINSTANCEPATH")
530
+
531
+ unless ((k = WBEM.kids(tt)).length == 2)
532
+ raise ParseError, "Expecting (LOCALNAMESPACEPATH, INSTANCENAME) got #{k.keys()}"
533
+ end
534
+ localnspath = WBEM.parse_localnamespacepath(k[0])
535
+ instancename = WBEM.parse_instancename(k[1])
536
+ instancename.namespace = localnspath
537
+ return instancename
538
+ end
539
+
540
+ def WBEM.parse_instancename(tt)
541
+ # """Parse XML INSTANCENAME into CIMInstanceName object."""
542
+
543
+ ## <!ELEMENT INSTANCENAME (KEYBINDING* | KEYVALUE? | VALUE.REFERENCE?)>
544
+ ## <!ATTLIST INSTANCENAME %ClassName;>
545
+
546
+ WBEM.check_node(tt, "INSTANCENAME", ["CLASSNAME"])
547
+
548
+ if ((k = WBEM.kids(tt)).length == 0)
549
+ # probably not ever going to see this, but it's valid
550
+ # according to the grammar
551
+ return CIMInstanceName.new(WBEM.attrs(tt)["CLASSNAME"], {})
552
+ end
553
+ classname = WBEM.attrs(tt)["CLASSNAME"]
554
+ w = WBEM.name(k[0])
555
+ if w == "KEYVALUE" or w == "VALUE.REFERENCE"
556
+ unless ((k = WBEM.kids(tt)).length == 1)
557
+ raise ParseError, "expected only one #{w} under #{WBEM.name(tt)}"
558
+ end
559
+
560
+ # FIXME: This is probably not the best representation of these forms...
561
+ return CIMInstanceName(classname, {nil => WBEM.parse_any(k[0])})
562
+ elsif w == "KEYBINDING"
563
+ kbs = {}
564
+ WBEM.list_of_various(tt, ["KEYBINDING"]).each { |kb| kbs.update(kb)}
565
+ return CIMInstanceName.new(classname, kbs)
566
+ else
567
+ raise ParseError, "unexpected node #{w} under #{WBEM.name(tt)}"
568
+ end
569
+ end
570
+
571
+ def WBEM.parse_objectpath(tt)
572
+ # """
573
+ # <!ELEMENT OBJECTPATH (INSTANCEPATH | CLASSPATH)>
574
+ # """
575
+
576
+ WBEM.check_node(tt, "OBJECTPATH")
577
+ child = WBEM.one_child(tt, ["INSTANCEPATH", "CLASSPATH"])
578
+ return [WBEM.name(tt), WBEM.attrs(tt), child]
579
+
580
+
581
+ end
582
+
583
+ def WBEM.parse_keybinding(tt)
584
+ ##<!ELEMENT KEYBINDING (KEYVALUE | VALUE.REFERENCE)>
585
+ ##<!ATTLIST KEYBINDING
586
+ ## %CIMName;>
587
+
588
+ # """Returns one-item dictionary from name to Python value."""
589
+
590
+ WBEM.check_node(tt, "KEYBINDING", ["NAME"])
591
+ child = WBEM.one_child(tt, ["KEYVALUE", "VALUE.REFERENCE"])
592
+ return {WBEM.attrs(tt)["NAME"] => child}
593
+ end
594
+
595
+ def WBEM.parse_keyvalue(tt)
596
+ ##<!ELEMENT KEYVALUE (#PCDATA)>
597
+ ##<!ATTLIST KEYVALUE
598
+ ## VALUETYPE (string | boolean | numeric) "string">
599
+
600
+ # """Parse VALUETYPE into Python primitive value"""
601
+
602
+ WBEM.check_node(tt, "KEYVALUE", [], ["VALUETYPE"], [], true)
603
+ vt = WBEM.attrs(tt).fetch("VALUETYPE", "string")
604
+ p = WBEM.pcdata(tt)
605
+ if vt == "string"
606
+ return p
607
+ elsif vt == "boolean"
608
+ return WBEM.unpack_boolean(p)
609
+ elsif vt == "numeric"
610
+ return p.strip().to_i
611
+ else
612
+ raise ParseError, "invalid VALUETYPE #{vt} in #{WBEM.name(tt)}"
613
+ end
614
+ end
615
+
616
+ #
617
+ # Object definition elements
618
+ #
619
+ def WBEM.parse_class(tt)
620
+ ## <!ELEMENT CLASS (QUALIFIER*, (PROPERTY | PROPERTY.ARRAY |
621
+ ## PROPERTY.REFERENCE)*, METHOD*)>
622
+ ## <!ATTLIST CLASS
623
+ ## %CIMName;
624
+ ## %SuperClass;>
625
+
626
+ # This doesn't check the ordering of elements, but it's not very important
627
+ WBEM.check_node(tt, "CLASS", ["NAME"], ["SUPERCLASS"],
628
+ ["QUALIFIER", "PROPERTY", "PROPERTY.REFERENCE",
629
+ "PROPERTY.ARRAY", "METHOD"])
630
+
631
+ obj = CIMClass.new(WBEM.attrs(tt)["NAME"])
632
+ obj.superclass = WBEM.attrs(tt)["SUPERCLASS"]
633
+
634
+ obj.properties = WBEM.byname(WBEM.list_of_matching(tt, ["PROPERTY", "PROPERTY.REFERENCE",
635
+ "PROPERTY.ARRAY"]))
636
+
637
+ obj.qualifiers = WBEM.byname(WBEM.list_of_matching(tt, ["QUALIFIER"]))
638
+ obj.cim_methods = list_of_matching(tt, ["METHOD"])
639
+
640
+ return obj
641
+ end
642
+
643
+ def WBEM.parse_instance(tt)
644
+ # """Return a CIMInstance.
645
+
646
+ # The instance contains the properties, qualifiers and classname for
647
+ # the instance"""
648
+
649
+ ##<!ELEMENT INSTANCE (QUALIFIER*, (PROPERTY | PROPERTY.ARRAY |
650
+ ## PROPERTY.REFERENCE)*)>
651
+ ##<!ATTLIST INSTANCE
652
+ ## %ClassName;>
653
+
654
+ WBEM.check_node(tt, "INSTANCE", ["CLASSNAME"],
655
+ ["QUALIFIER", "PROPERTY", "PROPERTY.ARRAY",
656
+ "PROPERTY.REFERENCE"])
657
+
658
+ ## XXX: This does not enforce ordering constraint
659
+
660
+ ## XXX: This does not enforce the constraint that there be only
661
+ ## one PROPERTY or PROPERTY.ARRAY.
662
+
663
+ ## TODO: Parse instance qualifiers
664
+ qualifiers = {}
665
+ props = WBEM.list_of_matching(tt, ["PROPERTY.REFERENCE", "PROPERTY", "PROPERTY.ARRAY"])
666
+
667
+ obj = CIMInstance.new(WBEM.attrs(tt)["CLASSNAME"])
668
+ obj.qualifiers = qualifiers
669
+ props.each { |p| obj[p.name] = p }
670
+ return obj
671
+ end
672
+
673
+ def WBEM.parse_qualifier(tt)
674
+ ## <!ELEMENT QUALIFIER (VALUE | VALUE.ARRAY)>
675
+ ## <!ATTLIST QUALIFIER %CIMName;
676
+ ## %CIMType; #REQUIRED
677
+ ## %Propagated;
678
+ ## %QualifierFlavor;>
679
+
680
+ WBEM.check_node(tt, "QUALIFIER", ["NAME", "TYPE"],
681
+ ["OVERRIDABLE", "TOSUBCLASS", "TOINSTANCE",
682
+ "TRANSLATABLE", "PROPAGATED"],
683
+ ["VALUE", "VALUE.ARRAY"])
684
+
685
+ a = WBEM.attrs(tt)
686
+
687
+ q = CIMQualifier.new(a["NAME"], WBEM.unpack_value(tt))
688
+
689
+ ## TODO: Lift this out?
690
+ ["OVERRIDABLE", "TOSUBCLASS", "TOINSTANCE", "TRANSLATABLE", "PROPAGATED"].each do |i|
691
+ rv = a[i]
692
+ unless ["true", "false", nil].include?(rv)
693
+ raise ParseError, "invalid value #{rv} for #{i} on #{WBEM.name(tt)}"
694
+ end
695
+ if rv == "true"
696
+ rv = true
697
+ elsif rv == "false"
698
+ rv = false
699
+ end
700
+ q.method("#{i.downcase()}=").call(rv)
701
+ end
702
+ return q
703
+ end
704
+
705
+ def WBEM.parse_property(tt)
706
+ # """Parse PROPERTY into a CIMProperty object.
707
+
708
+ # VAL is just the pcdata of the enclosed VALUE node."""
709
+
710
+ ## <!ELEMENT PROPERTY (QUALIFIER*, VALUE?)>
711
+ ## <!ATTLIST PROPERTY %CIMName;
712
+ ## %ClassOrigin;
713
+ ## %Propagated;
714
+ ## %CIMType; #REQUIRED>
715
+
716
+ ## TODO: Parse this into NAME, VALUE, where the value contains
717
+ ## magic fields for the qualifiers and the propagated flag.
718
+
719
+ WBEM.check_node(tt, "PROPERTY", ["TYPE", "NAME"],
720
+ ["NAME", "CLASSORIGIN", "PROPAGATED"],
721
+ ["QUALIFIER", "VALUE"])
722
+
723
+ quals = {}
724
+ WBEM.list_of_matching(tt, ["QUALIFIER"]).each { |q| quals[q.name] = q }
725
+ val = WBEM.unpack_value(tt)
726
+ a = WBEM.attrs(tt)
727
+
728
+ return CIMProperty.new(a["NAME"], val, a["TYPE"],
729
+ a["CLASSORIGIN"],
730
+ WBEM.unpack_boolean(a["PROPAGATED"]),
731
+ nil,
732
+ quals)
733
+
734
+ end
735
+
736
+ def WBEM.parse_property_array(tt)
737
+ # """
738
+ # <!ELEMENT PROPERTY.ARRAY (QUALIFIER*, VALUE.ARRAY?)>
739
+ # <!ATTLIST PROPERTY.ARRAY %CIMName;
740
+ # %CIMType; #REQUIRED
741
+ # %ArraySize;
742
+ # %ClassOrigin;
743
+ # %Propagated;>
744
+ # """
745
+
746
+ WBEM.check_node(tt, "PROPERTY.ARRAY", ["NAME", "TYPE"],
747
+ ["REFERENCECLASS", "CLASSORIGIN", "PROPAGATED",
748
+ "ARRAYSIZE"],
749
+ ["QUALIFIER", "VALUE.ARRAY"])
750
+
751
+ qualifiers = WBEM.byname(WBEM.list_of_matching(tt, ["QUALIFIER"]))
752
+ values = WBEM.unpack_value(tt)
753
+ a = WBEM.attrs(tt)
754
+ return CIMProperty.new(a["NAME"], values, a["TYPE"],
755
+ a["CLASSORIGIN"],
756
+ nil, true, qualifiers)
757
+ ## TODO qualifiers, other attributes
758
+ end
759
+
760
+ def WBEM.parse_property_reference(tt)
761
+ # """
762
+ # <!ELEMENT PROPERTY.REFERENCE (QUALIFIER*, (VALUE.REFERENCE)?)>
763
+ # <!ATTLIST PROPERTY.REFERENCE
764
+ # %CIMName;
765
+ # %ReferenceClass;
766
+ # %ClassOrigin;
767
+ # %Propagated;>
768
+ # """
769
+
770
+ WBEM.check_node(tt, "PROPERTY.REFERENCE", ["NAME"],
771
+ ["REFERENCECLASS", "CLASSORIGIN", "PROPAGATED"])
772
+
773
+ value = WBEM.list_of_matching(tt, ["VALUE.REFERENCE"])
774
+
775
+ if value.nil? or value.length == 0
776
+ value = nil
777
+ elsif value.length == 1
778
+ value = value[0]
779
+ else
780
+ raise ParseError, "Too many VALUE.REFERENCE elements."
781
+ end
782
+
783
+ attributes = WBEM.attrs(tt)
784
+ pref = CIMProperty.new(attributes["NAME"], value, "reference")
785
+
786
+ WBEM.list_of_matching(tt, ["QUALIFIER"]).each { |q| pref.qualifiers[q.name] = q}
787
+ if attributes.has_key?("REFERENCECLASS")
788
+ pref.reference_class = attributes["REFERENCECLASS"]
789
+ end
790
+ if attributes.has_key?("CLASSORIGIN")
791
+ pref.class_origin = attributes["CLASSORIGIN"]
792
+ end
793
+ if attributes.has_key?("PROPAGATED")
794
+ pref.propagated = attributes["PROPAGATED"]
795
+ end
796
+ return pref
797
+ end
798
+
799
+ def WBEM.parse_method(tt)
800
+ # """
801
+ # <!ELEMENT METHOD (QUALIFIER*, (PARAMETER | PARAMETER.REFERENCE |
802
+ # PARAMETER.ARRAY | PARAMETER.REFARRAY)*)>
803
+ # <!ATTLIST METHOD %CIMName;
804
+ # %CIMType; #IMPLIED
805
+ # %ClassOrigin;
806
+ # %Propagated;>
807
+ # """
808
+
809
+ WBEM.check_node(tt, "METHOD", ["NAME"],
810
+ ["TYPE", "CLASSORIGIN", "PROPAGATED"],
811
+ ["QUALIFIER", "PARAMETER", "PARAMETER.REFERENCE",
812
+ "PARAMETER.ARRAY", "PARAMETER.REFARRAY"])
813
+
814
+ qualifiers = WBEM.byname(WBEM.list_of_matching(tt, ["QUALIFIER"]))
815
+
816
+ parameters = WBEM.byname(WBEM.list_of_matching(tt, ["PARAMETER",
817
+ "PARAMETER.REFERENCE",
818
+ "PARAMETER.ARRAY",
819
+ "PARAMETER.REFARRAY",]))
820
+ a = WBEM.attrs(tt)
821
+ return CIMMethod.new(a["NAME"],
822
+ a["TYPE"],
823
+ parameters,
824
+ a["CLASSORIGIN"],
825
+ unpack_boolean(a["PROPAGATED"]),
826
+ qualifiers)
827
+ end
828
+
829
+ def WBEM.parse_parameter(tt)
830
+ # """
831
+ # <!ELEMENT PARAMETER (QUALIFIER*)>
832
+ # <!ATTLIST PARAMETER
833
+ # %CIMName;
834
+ # %CIMType; #REQUIRED>
835
+ # """
836
+
837
+ WBEM.check_node(tt, "PARAMETER", ["NAME", "TYPE"], [])
838
+
839
+ quals = {}
840
+ list_of_matching(tt, ['QUALIFIER']).each {|q| quals[q.name] = q }
841
+
842
+ a = WBEM.attrs(tt)
843
+
844
+ return CIMParameter.new(a["NAME"], a["TYPE"], nil, nil, nil, quals)
845
+ end
846
+
847
+ def WBEM.parse_parameter_reference(tt)
848
+ # """
849
+ # <!ELEMENT PARAMETER.REFERENCE (QUALIFIER*)>
850
+ # <!ATTLIST PARAMETER.REFERENCE
851
+ # %CIMName;
852
+ # %ReferenceClass;>
853
+ # """
854
+
855
+ WBEM.check_node(tt, "PARAMETER.REFERENCE", ["NAME"], ["REFERENCECLASS"])
856
+
857
+ quals = {}
858
+ list_of_matching(tt, ['QUALIFIER']).each {|q| quals[q.name] = q }
859
+
860
+ a = WBEM.attrs(tt)
861
+
862
+ return CIMParameter.new(a["NAME"], "reference", a['REFERENCECLASS'], nil, nil, quals)
863
+ end
864
+
865
+ def WBEM.parse_parameter_array(tt)
866
+ # """
867
+ # <!ELEMENT PARAMETER.ARRAY (QUALIFIER*)>
868
+ # <!ATTLIST PARAMETER.ARRAY
869
+ # %CIMName;
870
+ # %CIMType; #REQUIRED
871
+ # %ArraySize;>
872
+ # """
873
+
874
+ WBEM.check_node(tt, "PARAMETER.ARRAY", ["NAME", "TYPE"], ["ARRAYSIZE"])
875
+
876
+ quals = {}
877
+ list_of_matching(tt, ['QUALIFIER']).each {|q| quals[q.name] = q }
878
+
879
+ a = WBEM.attrs(tt)
880
+ array_size = a["ARRAYSIZE"]
881
+ array_size = array_size.to_i unless array_size.nil?
882
+
883
+ return CIMParameter.new(a["NAME"], a["TYPE"], nil, true, array_size, quals)
884
+ end
885
+
886
+ def WBEM.parse_parameter_refarray(tt)
887
+ # """
888
+ # <!ELEMENT PARAMETER.REFARRAY (QUALIFIER*)>
889
+ # <!ATTLIST PARAMETER.REFARRAY
890
+ # %CIMName;
891
+ # %ReferenceClass;
892
+ # %ArraySize;>
893
+ # """
894
+
895
+ WBEM.check_node(tt, "PARAMETER.REFARRAY", ["NAME"], ["REFERENCECLASS", "ARRAYSIZE"])
896
+
897
+ quals = {}
898
+ list_of_matching(tt, ['QUALIFIER']).each {|q| quals[q.name] = q }
899
+
900
+ a = WBEM.attrs(tt)
901
+ array_size = a["ARRAYSIZE"]
902
+ array_size = array_size.to_i unless array_size.nil?
903
+
904
+ return CIMParameter.new(a["NAME"], "reference", a["REFERENCECLASS"],
905
+ true, array_size, quals)
906
+ end
907
+
908
+ #
909
+ # Message elements
910
+ #
911
+ def WBEM.parse_message(tt)
912
+ # """
913
+ # <!ELEMENT MESSAGE (SIMPLEREQ | MULTIREQ | SIMPLERSP | MULTIRSP)>
914
+ # <!ATTLIST MESSAGE
915
+ # ID CDATA #REQUIRED
916
+ # PROTOCOLVERSION CDATA #REQUIRED>
917
+ # """
918
+ WBEM.check_node(tt, "MESSAGE", ["ID", "PROTOCOLVERSION"])
919
+ messages = WBEM.one_child(
920
+ tt, ["SIMPLEREQ", "MULTIREQ", "SIMPLERSP", "MULTIRSP"])
921
+ unless messages[0].is_a?(Array)
922
+ # make single and multi forms consistent
923
+ messages = [messages]
924
+ end
925
+ return [WBEM.name(tt), WBEM.attrs(tt), messages]
926
+ end
927
+
928
+ def WBEM.parse_multireq(tt)
929
+ raise ParseError, "MULTIREQ parser not implemented"
930
+ end
931
+
932
+ def WBEM.parse_multiexpreq(tt)
933
+ raise ParseError, "MULTIEXPREQ parser not implemented"
934
+ end
935
+
936
+ def WBEM.parse_simplereq(tt)
937
+ # """
938
+ # <!ELEMENT SIMPLEREQ (IMETHODCALL | METHODCALL)>
939
+ # """
940
+
941
+ WBEM.check_node(tt, "SIMPLEREQ")
942
+ child = WBEM.one_child(tt, ["IMETHODCALL", "METHODCALL"])
943
+ return [WBEM.kids(tt)[0][0], child]
944
+ end
945
+
946
+ def WBEM.parse_simpleexpreq(tt)
947
+ raise ParseError, "SIMPLEEXPREQ parser not implemented"
948
+ end
949
+
950
+ def WBEM.parse_imethodcall(tt)
951
+ # """
952
+ # <!ELEMENT IMETHODCALL (LOCALNAMESPACEPATH, IPARAMVALUE*)>
953
+ # <!ATTLIST IMETHODCALL
954
+ # %CIMName;>
955
+ # """
956
+
957
+ WBEM.check_node(tt, "IMETHODCALL", ["NAME"])
958
+ if ((k = WBEM.kids(tt)).length < 1)
959
+ raise ParseError, "Expecting LOCALNAMESPACEPATH, got nothing"
960
+ end
961
+ localnspath = WBEM.parse_localnamespacepath(k[0])
962
+ params = k[1..-1].collect { |x| WBEM.parse_iparamvalue(x) }
963
+ return [WBEM.name(tt), WBEM.attrs(tt), localnspath, params]
964
+ end
965
+
966
+ def WBEM.parse_methodcall(tt)
967
+ raise ParseError, "METHODCALL parser not implemented"
968
+ end
969
+
970
+ def WBEM.parse_expmethodcall(tt)
971
+ raise ParseError, "EXPMETHODCALL parser not implemented"
972
+ end
973
+
974
+ def WBEM.parse_paramvalue(tt)
975
+ ## <!ELEMENT PARAMVALUE (VALUE | VALUE.REFERENCE | VALUE.ARRAY |
976
+ ## VALUE.REFARRAY)?>
977
+ ## <!ATTLIST PARAMVALUE
978
+ ## %CIMName;
979
+ ## %ParamType; #IMPLIED>
980
+
981
+ ## Version 2.1.1 of the DTD lacks the %ParamType attribute but it
982
+ ## is present in version 2.2. Make it optional to be backwards
983
+ ## compatible.
984
+
985
+ WBEM.check_node(tt, "PARAMVALUE", ["NAME"], ["PARAMTYPE"])
986
+
987
+ child = WBEM.optional_child(tt,
988
+ ["VALUE", "VALUE.REFERENCE", "VALUE.ARRAY",
989
+ "VALUE.REFARRAY",])
990
+
991
+ if WBEM.attrs(tt).has_key?("PARAMTYPE")
992
+ paramtype = WBEM.attrs(tt)["PARAMTYPE"]
993
+ else
994
+ paramtype = nil
995
+ end
996
+ return [WBEM.attrs(tt)["NAME"], paramtype, child]
997
+ end
998
+
999
+ def WBEM.parse_iparamvalue(tt)
1000
+ ## <!ELEMENT IPARAMVALUE (VALUE | VALUE.ARRAY | VALUE.REFERENCE |
1001
+ ## INSTANCENAME | CLASSNAME | QUALIFIER.DECLARATION |
1002
+ ## CLASS | INSTANCE | VALUE.NAMEDINSTANCE)?>
1003
+ ## <!ATTLIST IPARAMVALUE %CIMName;>
1004
+
1005
+ # """Returns NAME, VALUE pair."""
1006
+
1007
+ WBEM.check_node(tt, "IPARAMVALUE", ["NAME"], [])
1008
+
1009
+ child = WBEM.optional_child(tt,
1010
+ ["VALUE", "VALUE.ARRAY", "VALUE.REFERENCE",
1011
+ "INSTANCENAME", "CLASSNAME",
1012
+ "QUALIFIER.DECLARATION", "CLASS", "INSTANCE",
1013
+ "VALUE.NAMEDINSTANCE"])
1014
+ ## TODO: WBEM.unpack_value() where appropriate.
1015
+ return [WBEM.attrs(tt)["NAME"], child ]
1016
+ end
1017
+
1018
+ def WBEM.parse_expparamvalue(tt)
1019
+ raise ParseError, "EXPPARAMVALUE parser not implemented"
1020
+ end
1021
+
1022
+ def WBEM.parse_multirsp(tt)
1023
+ raise ParseError, "MULTIRSP parser not implemented"
1024
+ end
1025
+
1026
+ def WBEM.parse_multiexprsp(tt)
1027
+ raise ParseError, "MULTIEXPRSP parser not implemented"
1028
+ end
1029
+
1030
+ def WBEM.parse_simplersp(tt)
1031
+ ## <!ELEMENT SIMPLERSP (METHODRESPONSE | IMETHODRESPONSE)>
1032
+ WBEM.check_node(tt, "SIMPLERSP", [], [])
1033
+ child = WBEM.one_child(tt, ["METHODRESPONSE", "IMETHODRESPONSE"])
1034
+ return [WBEM.name(tt), WBEM.attrs(tt), child]
1035
+ end
1036
+
1037
+ def WBEM.parse_simpleexprsp(tt)
1038
+ raise ParseError, "SIMPLEEXPRSP parser not implemented"
1039
+ end
1040
+
1041
+ def WBEM.parse_methodresponse(tt)
1042
+ ## <!ELEMENT METHODRESPONSE (ERROR | (RETURNVALUE?, PARAMVALUE*))>
1043
+ ## <!ATTLIST METHODRESPONSE
1044
+ ## %CIMName;>
1045
+
1046
+ WBEM.check_node(tt, "METHODRESPONSE", ["NAME"], [])
1047
+
1048
+ return [WBEM.name(tt), WBEM.attrs(tt), WBEM.list_of_various(tt, ["ERROR", "RETURNVALUE",
1049
+ "PARAMVALUE"])]
1050
+ end
1051
+
1052
+ def WBEM.parse_expmethodresponse(tt)
1053
+ raise ParseError, "EXPMETHODRESPONSE parser not implemented"
1054
+ end
1055
+
1056
+ def WBEM.parse_imethodresponse(tt)
1057
+ ## <!ELEMENT IMETHODRESPONSE (ERROR | IRETURNVALUE?)>
1058
+ ## <!ATTLIST IMETHODRESPONSE %CIMName;>
1059
+ WBEM.check_node(tt, "IMETHODRESPONSE", ["NAME"], [])
1060
+ return [WBEM.name(tt), WBEM.attrs(tt), WBEM.optional_child(tt, ["ERROR", "IRETURNVALUE"])]
1061
+ end
1062
+
1063
+ def WBEM.parse_error(tt)
1064
+ # """
1065
+ # <!ELEMENT ERROR EMPTY>
1066
+ # <!ATTLIST ERROR
1067
+ # CODE CDATA #REQUIRED
1068
+ # DESCRIPTION CDATA #IMPLIED>
1069
+ # """
1070
+
1071
+ ## TODO: Return a CIMError object, not a tuple
1072
+ WBEM.check_node(tt, "ERROR", ["CODE"], ["DESCRIPTION"])
1073
+ return [WBEM.name(tt), WBEM.attrs(tt), nil]
1074
+ end
1075
+
1076
+ def WBEM.parse_returnvalue(tt)
1077
+ ## <!ELEMENT RETURNVALUE (VALUE | VALUE.ARRAY | VALUE.REFERENCE |
1078
+ ## VALUE.REFARRAY)>
1079
+ ## <!ATTLIST RETURNVALUE %ParamType; #IMPLIED>
1080
+
1081
+ ## Version 2.1.1 of the DTD lacks the %ParamType attribute but it
1082
+ ## is present in version 2.2. Make it optional to be backwards
1083
+ ## compatible.
1084
+
1085
+ WBEM.check_node(tt, "RETURNVALUE", [], ["PARAMTYPE"])
1086
+ return name[(tt), WBEM.attrs(tt), WBEM.one_child(tt, ["VALUE", "VALUE.ARRAY",
1087
+ "VALUE.REFERENCE",
1088
+ "VALUE.REFARRAY"])]
1089
+ end
1090
+
1091
+ def WBEM.parse_ireturnvalue(tt)
1092
+ ## <!ELEMENT IRETURNVALUE (CLASSNAME* | INSTANCENAME* | VALUE* |
1093
+ ## VALUE.OBJECTWITHPATH* |
1094
+ ## VALUE.OBJECTWITHLOCALPATH* | VALUE.OBJECT* |
1095
+ ## OBJECTPATH* | QUALIFIER.DECLARATION* |
1096
+ ## VALUE.ARRAY? | VALUE.REFERENCE? | CLASS* |
1097
+ ## INSTANCE* | VALUE.NAMEDINSTANCE*)>
1098
+
1099
+ WBEM.check_node(tt, "IRETURNVALUE", [], [])
1100
+
1101
+ # XXX: doesn"t prohibit the case of only one VALUE.ARRAY or
1102
+ # VALUE.REFERENCE. But why is that required? Why can it return
1103
+ # multiple VALUEs but not multiple VALUE.REFERENCEs?
1104
+
1105
+ values = WBEM.list_of_same(tt, ["CLASSNAME", "INSTANCENAME",
1106
+ "VALUE", "VALUE.OBJECTWITHPATH", "VALUE.OBJECT",
1107
+ "OBJECTPATH", "QUALIFIER.DECLARATION",
1108
+ "VALUE.ARRAY", "VALUE.REFERENCE",
1109
+ "CLASS", "INSTANCE",
1110
+ "VALUE.NAMEDINSTANCE",])
1111
+ ## TODO: Call WBEM.unpack_value if appropriate
1112
+ return [WBEM.name(tt), WBEM.attrs(tt), values]
1113
+ end
1114
+
1115
+ #
1116
+ # Object naming and locating elements
1117
+ #
1118
+
1119
+ class MethodHelper
1120
+
1121
+ end
1122
+ def WBEM.parse_any(tt)
1123
+ # """Parse any fragment of XML."""
1124
+ h = MethodHelper.new
1125
+ nodename = WBEM.name(tt).downcase().tr(".", "_")
1126
+ fn_name = "parse_" + nodename
1127
+ method = self.method(fn_name)
1128
+ unless method
1129
+ raise ParseError, "no parser #{fn_name} for node type #{WBEM.name(tt)}"
1130
+ end
1131
+ return method.call(tt)
1132
+ end
1133
+
1134
+ def WBEM.unpack_value(tt)
1135
+ # """Find VALUE or VALUE.ARRAY under TT and convert to a Python value.
1136
+
1137
+ # Looks at the TYPE of the node to work out how to decode it.
1138
+ # Handles nodes with no value (e.g. in CLASS.)
1139
+ # """
1140
+ val = WBEM.list_of_matching(tt, ["VALUE", "VALUE.ARRAY"])
1141
+
1142
+ ## TODO: Handle VALUE.REFERENCE, VALUE.REFARRAY
1143
+
1144
+ valtype = WBEM.attrs(tt)["TYPE"]
1145
+ raw_val = WBEM.list_of_matching(tt, ["VALUE", "VALUE.ARRAY"])
1146
+ if raw_val.empty?
1147
+ return nil
1148
+ elsif raw_val.length > 1
1149
+ raise ParseError, "more than one VALUE or VALUE.ARRAY under #{WBEM.name(tt)}"
1150
+ end
1151
+ raw_val = raw_val[0]
1152
+
1153
+ if raw_val.is_a?(Array)
1154
+ return raw_val.collect { |x| tocimobj(valtype, x) }
1155
+ elif raw_val.empty?
1156
+ return nil
1157
+ else
1158
+ return WBEM.tocimobj(valtype, raw_val)
1159
+ end
1160
+ end
1161
+
1162
+ def WBEM.unpack_boolean(p)
1163
+ # """Unpack a boolean, represented as "TRUE" or "FALSE" in CIM."""
1164
+ if p.nil?
1165
+ return nil
1166
+ end
1167
+ ## CIM-XML says "These values MUST be treated as case-insensitive"
1168
+ ## (even though the XML definition requires them to be lowercase.)
1169
+
1170
+ p = p.strip().downcase() # ignore space
1171
+ if p == "true"
1172
+ return true
1173
+ elsif p == "false"
1174
+ return false
1175
+ elsif p == ""
1176
+ return nil
1177
+ else
1178
+ raise ParseError, "invalid boolean #{p}"
1179
+ end
1180
+ end
1181
+ end