1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 '''Tuple parser for the XML schema representing CIM messages.
25
26 This framework is meant to add some value to the tuple-tree
27 representation of CIM in XML by having the following properties:
28
29 - Silently ignoring whitespace text elements
30
31 - Conversion from tuple-tree representation into a python dictionary
32 which can then be accessed in a readable fashion.
33
34 - Validation of the XML elements and attributes without having to
35 use the DTD file or any external tools.
36
37 '''
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79 import string
80 from types import StringTypes
81
82 from pywbem import cim_obj, tupletree
83 from pywbem.cim_obj import CIMInstance, CIMInstanceName, CIMClass, \
84 CIMClassName, CIMProperty, CIMMethod, \
85 CIMParameter, CIMQualifier, CIMQualifierDeclaration
86
87 __all__ = ['ParseError', 'parse_cim', 'parse_any']
88
90 """This exception is raised when there is a validation error detected
91 by the parser."""
92 pass
93
94
96 """Return only the tuples in a list.
97
98 In a tupletree, tuples correspond to XML elements. Useful for
99 stripping out whitespace data in a child list."""
100
101 if l is None:
102 return []
103 else:
104 return [x for x in l if type(x) == tuple]
105
106
108 """Return the concatenated character data within a tt.
109
110 The tt must not have non-character children."""
111 for x in tt[2]:
112 if not isinstance(x, StringTypes):
113 raise ParseError, 'unexpected node %s under %s' % (`x`, `tt`)
114 return ''.join(tt[2])
115
116
119
120
123
124
126 return filter_tuples(tt[2])
127
128
129 -def check_node(tt, nodename, required_attrs=[], optional_attrs=[],
130 allowed_children=None,
131 allow_pcdata=False):
132 """Check static local constraints on a single node.
133
134 The node must have the given name. The required attrs must be
135 present, and the optional attrs may be.
136
137 If allowed_children is not None, the node may have children of the
138 given types. It can be [] for nodes that may not have any
139 children. If it's None, it is assumed the children are validated
140 in some other way.
141
142 If allow_pcdata is true, then non-whitespace text children are allowed.
143 (Whitespace text nodes are always allowed.)
144 """
145
146 if name(tt) <> nodename:
147 raise ParseError('expected node type %s, not %s' %
148 (nodename, name(tt)))
149
150
151 tt_attrs = {}
152 if attrs(tt) is not None:
153 tt_attrs = attrs(tt).copy()
154
155 for attr in required_attrs:
156 if not tt_attrs.has_key(attr):
157 raise ParseError('expected %s attribute on %s node, but only '
158 'have %s' % (attr, name(tt), attrs(tt).keys()))
159 del tt_attrs[attr]
160
161 for attr in optional_attrs:
162 if tt_attrs.has_key(attr):
163 del tt_attrs[attr]
164
165 if len(tt_attrs.keys()) > 0:
166 raise ParseError('invalid extra attributes %s' % tt_attrs.keys())
167
168 if allowed_children is not None:
169 for c in kids(tt):
170 if name(c) not in allowed_children:
171 raise ParseError('unexpected node %s under %s; wanted %s'
172 % (name(c), name(tt), allowed_children))
173
174 if not allow_pcdata:
175 for c in tt[2]:
176 if isinstance(c, StringTypes):
177 if c.lstrip(' \t\n') <> '':
178 raise ParseError('unexpected non-blank pcdata node %s '
179 'under %s' % (`c`, name(tt)))
180
181
183 """Parse children of a node with exactly one child node.
184
185 PCData is ignored.
186 """
187
188 k = kids(tt)
189
190 if len(k) <> 1:
191 raise ParseError('In element %s with attributes %s, expected just '\
192 'one child element %s, but got child elements %s' %\
193 (name(tt), attrs(tt), acceptable, [t[0] for t in k]))
194
195 child = k[0]
196
197 if name(child) not in acceptable:
198 raise ParseError('In element %s with attributes %s, expected one '\
199 'child element %s, but got child element %s' %\
200 (name(tt), attrs(tt), acceptable, name(child)))
201
202 return parse_any(child)
203
204
206 """Parse exactly zero or one of a list of elements from the
207 child nodes."""
208
209 k = kids(tt)
210
211 if len(k) > 1:
212 raise ParseError('In element %s with attributes %s, expected zero or '\
213 'one child element %s, but got child elements %s' %\
214 (name(tt), attrs(tt), allowed, [t[0] for t in k]))
215 elif len(k) == 1:
216 return one_child(tt, allowed)
217 else:
218 return None
219
220
222 """Parse zero or more of a list of elements from the child nodes.
223
224 Each element of the list can be any type from the list of acceptable
225 nodes."""
226
227 r = []
228
229 for child in kids(tt):
230 if name(child) not in acceptable:
231 raise ParseError('In element %s with attributes %s, expected zero '\
232 'or more child elements %s, but got child element %s' %\
233 (name(tt), attrs(tt), acceptable, name(child)))
234 r.append(parse_any(child))
235
236 return r
237
238
240 """Parse only the children of particular types under tt.
241
242 Other children are ignored rather than giving an error."""
243
244 r = []
245
246 for child in kids(tt):
247 if name(child) not in matched:
248 continue
249 r.append(parse_any(child))
250
251 return r
252
253
255 """Parse a list of elements from child nodes.
256
257 The children can be any of the listed acceptable types, but they
258 must all be the same.
259 """
260
261 k = kids(tt)
262 if not k:
263 return []
264
265 w = name(k[0])
266 if w not in acceptable:
267 raise ParseError('In element %s with attributes %s, expected child '\
268 'elements %s, but got child element %s' %\
269 (name(tt), attrs(tt), acceptable, w))
270 r = []
271 for child in k:
272 if name(child) <> w:
273 raise ParseError('In element %s with attributes %s, expected '\
274 'sequence of only child elements %s, but got child '\
275 'element %s' % (name(tt), attrs(tt), w, name(child)))
276 r.append(parse_any(child))
277
278 return r
279
280
282 raise ParseError('parser for %s not implemented' % name(tt))
283
284
285
286
287
289 """
290 <!ELEMENT CIM (MESSAGE | DECLARATION)>
291 <!ATTLIST CIM
292 CIMVERSION CDATA #REQUIRED
293 DTDVERSION CDATA #REQUIRED>
294 """
295
296 check_node(tt, 'CIM', ['CIMVERSION', 'DTDVERSION'])
297
298 if not attrs(tt)['CIMVERSION'].startswith('2.'):
299 raise ParseError('CIMVERSION is %s, expected 2.x.y' %
300 attrs(tt)['CIMVERSION'])
301
302 child = one_child(tt, ['MESSAGE', 'DECLARATION'])
303
304 return name(tt), attrs(tt), child
305
306
307
308
309
310
312 """
313 <!ELEMENT DECLARATION ( DECLGROUP | DECLGROUP.WITHNAME |
314 DECLGROUP.WITHPATH )+>
315
316 Note: We only support the DECLGROUP child, at this point.
317 """
318
319 check_node(tt, 'DECLARATION')
320
321 child = one_child(tt, ['DECLGROUP'])
322
323 return name(tt), attrs(tt), child
324
325
327 """
328 <!ELEMENT DECLGROUP ( (LOCALNAMESPACEPATH|NAMESPACEPATH)?,
329 QUALIFIER.DECLARATION*, VALUE.OBJECT* )>
330
331 Note: We only support the QUALIFIER.DECLARATION and VALUE.OBJECT
332 children, and with a multiplicity of 1, at this point.
333 """
334
335 check_node(tt, 'DECLGROUP')
336
337 child = one_child(tt, ['QUALIFIER.DECLARATION', 'VALUE.OBJECT'])
338
339 return name(tt), attrs(tt), child
340
341
342
343
344
345
347 '''Return VALUE contents as a string'''
348
349 check_node(tt, 'VALUE', [], [], [], True)
350
351 return pcdata(tt)
352
353
355 """Return list of strings."""
356
357 check_node(tt, 'VALUE.ARRAY', [], [], ['VALUE'])
358
359 return list_of_same(tt, ['VALUE'])
360
361
363 """
364 <!ELEMENT VALUE.REFERENCE (CLASSPATH | LOCALCLASSPATH | CLASSNAME |
365 INSTANCEPATH | LOCALINSTANCEPATH |
366 INSTANCENAME)>
367 """
368
369 check_node(tt, 'VALUE.REFERENCE', [])
370
371 child = one_child(tt,
372 ['CLASSPATH', 'LOCALCLASSPATH', 'CLASSNAME',
373 'INSTANCEPATH', 'LOCALINSTANCEPATH',
374 'INSTANCENAME'])
375
376
377 return child
378
379
381 """
382 <!ELEMENT VALUE.REFARRAY (VALUE.REFERENCE*)>
383 """
384
385 check_node(tt, 'VALUE.REFARRAY')
386
387 children = list_of_various(tt, ['VALUE.REFERENCE'])
388
389
390 return children
391
392
394 """
395 <!ELEMENT VALUE.OBJECT (CLASS | INSTANCE)>
396 """
397
398 check_node(tt, 'VALUE.OBJECT')
399
400 child = one_child(tt, ['CLASS', 'INSTANCE'])
401
402 return (name(tt), attrs(tt), child)
403
404
406 """
407 <!ELEMENT VALUE.NAMEDINSTANCE (INSTANCENAME, INSTANCE)>
408 """
409
410 check_node(tt, 'VALUE.NAMEDINSTANCE')
411
412 k = kids(tt)
413 if len(k) <> 2:
414 raise ParseError('expecting (INSTANCENAME, INSTANCE), got %s' % `k`)
415
416 instancename = parse_instancename(k[0])
417 instance = parse_instance(k[1])
418
419 instance.path = instancename
420
421 return instance
422
423
425 """
426 <!ELEMENT VALUE.NAMEDOBJECT (CLASS | (INSTANCENAME, INSTANCE))>
427 """
428
429 check_node(tt, 'VALUE.NAMEDOBJECT')
430
431 k = kids(tt)
432 if len(k) == 1:
433 object = parse_class(k[0])
434 elif len(k) == 2:
435 path = parse_instancename(kids(tt)[0])
436 object = parse_instance(kids(tt)[1])
437
438 object.path = path
439 else:
440 raise ParseError('Expecting one or two elements, got %s' %
441 `kids(tt)`)
442
443 return (name(tt), attrs(tt), object)
444
445
447 """
448 <!ELEMENT VALUE.OBJECTWITHLOCALPATH ((LOCALCLASSPATH, CLASS) |
449 (LOCALINSTANCEPATH, INSTANCE))>
450 """
451
452 check_node(tt, 'VALUE.OBJECTWITHLOCALPATH')
453
454 if len(kids(tt)) != 2:
455 raise ParseError('Expecting two elements, got %s' %
456 len(kids(tt)));
457
458 if kids(tt)[0][0] == 'LOCALCLASSPATH':
459 object = (parse_localclasspath(kids(tt)[0]),
460 parse_class(kids(tt)[1]))
461 else:
462 path = parse_localinstancepath(kids(tt)[0])
463 object = parse_instance(kids(tt)[1])
464
465 object.path = path
466
467 return (name(tt), attrs(tt), object)
468
470 """
471 <!ELEMENT VALUE.OBJECTWITHPATH ((CLASSPATH, CLASS) |
472 (INSTANCEPATH, INSTANCE))>
473 """
474
475 check_node(tt, 'VALUE.OBJECTWITHPATH')
476
477 k = kids(tt)
478
479 if len(k) != 2:
480 raise ParseError('Expecting two elements, got %s' % k)
481
482 if name(k[0]) == 'CLASSPATH':
483 object = (parse_classpath(k[0]),
484 parse_class(k[1]))
485 else:
486 path = parse_instancepath(k[0])
487 object = parse_instance(k[1])
488
489 object.path = path
490
491 return (name(tt), attrs(tt), object)
492
493
494
495
496
498 """
499 <!ELEMENT NAMESPACEPATH (HOST, LOCALNAMESPACEPATH)>
500 """
501
502 check_node(tt, 'NAMESPACEPATH')
503
504 if len(kids(tt)) != 2:
505 raise ParseError('Expecting (HOST, LOCALNAMESPACEPATH) '
506 'got %s' % kids(tt).keys())
507
508 host = parse_host(kids(tt)[0])
509 localnspath = parse_localnamespacepath(kids(tt)[1])
510
511 return (host, localnspath)
512
513
515 """
516 <!ELEMENT LOCALNAMESPACEPATH (NAMESPACE+)>
517 """
518
519 check_node(tt, 'LOCALNAMESPACEPATH', [], [], ['NAMESPACE'])
520
521 if len(kids(tt)) == 0:
522 raise ParseError('Expecting one or more of NAMESPACE, got nothing')
523
524 ns_list = list_of_various(tt, ['NAMESPACE'])
525
526 return string.join(ns_list, '/')
527
528
530 """
531 <!ELEMENT HOST (#PCDATA)>
532 """
533
534 check_node(tt, 'HOST', allow_pcdata=True)
535
536 return pcdata(tt)
537
538
540 """
541 <!ELEMENT NAMESPACE EMPTY>
542 <!ATTLIST NAMESPACE
543 %CIMName;>
544 """
545
546 check_node(tt, 'NAMESPACE', ['NAME'], [], [])
547
548 return attrs(tt)['NAME']
549
550
552 """
553 <!ELEMENT CLASSPATH (NAMESPACEPATH, CLASSNAME)>
554 """
555
556 check_node(tt, 'CLASSPATH')
557
558 if len(kids(tt)) != 2:
559 raise ParseError('Expecting (NAMESPACEPATH, CLASSNAME) '
560 'got %s' % kids(tt).keys())
561
562 nspath = parse_namespacepath(kids(tt)[0])
563 classname = parse_classname(kids(tt)[1])
564
565 return CIMClassName(classname.classname,
566 host=nspath[0], namespace=nspath[1])
567
568
570 """
571 <!ELEMENT LOCALCLASSPATH (LOCALNAMESPACEPATH, CLASSNAME)>
572 """
573
574 check_node(tt, 'LOCALCLASSPATH')
575
576 if len(kids(tt)) != 2:
577 raise ParseError('Expecting (LOCALNAMESPACEPATH, CLASSNAME) '
578 'got %s' % kids(tt).keys())
579
580 localnspath = parse_localnamespacepath(kids(tt)[0])
581 classname = parse_classname(kids(tt)[1])
582
583 return CIMClassName(classname.classname, namespace=localnspath)
584
586 """
587 <!ELEMENT CLASSNAME EMPTY>
588 <!ATTLIST CLASSNAME
589 %CIMName;>
590 """
591 check_node(tt, 'CLASSNAME', ['NAME'], [], [])
592 return CIMClassName(attrs(tt)['NAME'])
593
594
596 """
597 <!ELEMENT INSTANCEPATH (NAMESPACEPATH, INSTANCENAME)>
598 """
599
600 check_node(tt, 'INSTANCEPATH')
601
602 if len(kids(tt)) != 2:
603 raise ParseError('Expecting (NAMESPACEPATH, INSTANCENAME), got %s'
604 % `kids(tt)`)
605
606 nspath = parse_namespacepath(kids(tt)[0])
607 instancename = parse_instancename(kids(tt)[1])
608
609 instancename.host = nspath[0]
610 instancename.namespace = nspath[1]
611
612 return instancename
613
615 """
616 <!ELEMENT LOCALINSTANCEPATH (LOCALNAMESPACEPATH, INSTANCENAME)>
617 """
618
619 check_node(tt, 'LOCALINSTANCEPATH')
620
621 if len(kids(tt)) != 2:
622 raise ParseError('Expecting (LOCALNAMESPACEPATH, INSTANCENAME), '
623 'got %s' % kids(tt).keys())
624
625 localnspath = parse_localnamespacepath(kids(tt)[0])
626 instancename = parse_instancename(kids(tt)[1])
627
628 instancename.namespace = localnspath
629
630 return instancename
631
633 """Parse XML INSTANCENAME into CIMInstanceName object."""
634
635
636
637
638 check_node(tt, 'INSTANCENAME', ['CLASSNAME'])
639
640 if len(kids(tt)) == 0:
641
642
643 return CIMInstanceName(attrs(tt)['CLASSNAME'], {})
644
645 k0 = kids(tt)[0]
646 w = name(k0)
647
648 classname = attrs(tt)['CLASSNAME']
649
650 if w == 'KEYVALUE' or w == 'VALUE.REFERENCE':
651 if len(kids(tt)) != 1:
652 raise ParseError('expected only one %s under %s' %
653 w, name(tt))
654
655
656 val = parse_any(k0)
657 return CIMInstanceName(classname, {None: val})
658 elif w == 'KEYBINDING':
659 kbs = {}
660 for kb in list_of_various(tt, ['KEYBINDING']):
661 kbs.update(kb)
662 return CIMInstanceName(classname, kbs)
663 else:
664 raise ParseError('unexpected node %s under %s' %
665 (name(kids(tt)[0]), name(tt)))
666
667
669 """
670 <!ELEMENT OBJECTPATH (INSTANCEPATH | CLASSPATH)>
671 """
672
673 check_node(tt, 'OBJECTPATH')
674
675 child = one_child(tt, ['INSTANCEPATH', 'CLASSPATH'])
676
677 return (name(tt), attrs(tt), child)
678
679
680
682
683
684
685
686 """Returns one-item dictionary from name to Python value."""
687
688 check_node(tt, 'KEYBINDING', ['NAME'])
689
690 child = one_child(tt, ['KEYVALUE', 'VALUE.REFERENCE'])
691
692 return {attrs(tt)['NAME']: child}
693
694
696
697
698
699
700
701
702 """Parse VALUETYPE into Python primitive value"""
703
704 check_node(tt, 'KEYVALUE', ['VALUETYPE'], ['TYPE'], [], True)
705
706 p = pcdata(tt)
707
708 if not attrs(tt).has_key('VALUETYPE'):
709 return p;
710
711 vt = attrs(tt).get('VALUETYPE')
712
713 if vt == 'string':
714 return p
715 elif vt == 'boolean':
716 return unpack_boolean(p)
717 elif vt == 'numeric':
718
719 try:
720
721
722
723
724
725
726 return int(p.strip())
727 except ValueError, e:
728 raise ParseError('invalid numeric %s under %s' %
729 (`p`, name(tt)))
730 else:
731 raise ParseError('invalid VALUETYPE %s in %s',
732 vt, name(tt))
733
734
735
736
737
738
740
741
742
743
744
745
746
747 check_node(tt, 'CLASS', ['NAME'], ['SUPERCLASS'],
748 ['QUALIFIER', 'PROPERTY', 'PROPERTY.REFERENCE',
749 'PROPERTY.ARRAY', 'METHOD'])
750
751 superclass = attrs(tt).get('SUPERCLASS')
752
753
754 properties = cim_obj.byname(list_of_matching(tt, ['PROPERTY',
755 'PROPERTY.REFERENCE',
756 'PROPERTY.ARRAY']))
757
758 qualifiers = cim_obj.byname(list_of_matching(tt, ['QUALIFIER']))
759 methods = cim_obj.byname(list_of_matching(tt, ['METHOD']))
760
761 return CIMClass(attrs(tt)['NAME'],
762 superclass=superclass,
763 properties=properties,
764 qualifiers=qualifiers,
765 methods=methods)
766
767
769 """Return a CIMInstance.
770
771 The instance contains the properties, qualifiers and classname for
772 the instance"""
773
774
775
776
777
778
779 check_node(tt, 'INSTANCE', ['CLASSNAME'],
780 ['QUALIFIER', 'PROPERTY', 'PROPERTY.ARRAY',
781 'PROPERTY.REFERENCE'])
782
783
784
785
786
787
788
789 qualifiers = {}
790 props = list_of_matching(tt, ['PROPERTY.REFERENCE', 'PROPERTY',
791 'PROPERTY.ARRAY'])
792
793 obj = CIMInstance(attrs(tt)['CLASSNAME'],
794 qualifiers=qualifiers)
795
796 [obj.__setitem__(p.name, p) for p in props]
797
798 return obj
799
801
802
803
804
805
806
807
808
809
810 check_node(tt, 'SCOPE', [],
811 ['CLASS', 'ASSOCIATION', 'REFERENCE', 'PROPERTY', 'METHOD',
812 'PARAMETER', 'INDICATION'], [])
813 return dict([(k, v.lower() == 'true') for k, v in attrs(tt).items()])
814
816
817
818
819
820
821
822
823
824 check_node(tt, 'QUALIFIER.DECLARATION',
825 ['NAME', 'TYPE'],
826 ['ISARRAY', 'ARRAYSIZE', 'OVERRIDABLE', 'TOSUBCLASS',
827 'TOINSTANCE', 'TRANSLATABLE'],
828 ['SCOPE', 'VALUE', 'VALUE.ARRAY'])
829
830 a = attrs(tt)
831 qname = a['NAME']
832 type = a['TYPE']
833 try:
834 is_array = a['ISARRAY'].lower() == 'true'
835 except KeyError:
836 is_array = False
837 try:
838 array_size = int(a['ARRAYSIZE'])
839 except KeyError:
840 array_size = None
841
842 flavors = {}
843 for f in ['OVERRIDABLE', 'TOSUBCLASS', 'TOINSTANCE', 'TRANSLATABLE']:
844 try:
845 flavors[f.lower()] = a[f].lower() == 'true'
846 except KeyError:
847 pass
848
849 scopes = None
850 value = None
851 for child in kids(tt):
852 if name(child) == 'SCOPE':
853 if scopes is not None:
854 raise ParseError("Multiple SCOPE tags encountered")
855 scopes = parse_any(child)
856 else:
857 if value is not None:
858 raise ParseError("Multiple VALUE/VALUE.ARRAY tags encountered")
859 value = cim_obj.tocimobj(type, parse_any(child))
860
861 return CIMQualifierDeclaration(qname, type, value, is_array,
862 array_size, scopes, **flavors)
863
864
866
867
868
869
870
871
872 check_node(tt, 'QUALIFIER', ['NAME', 'TYPE'],
873 ['OVERRIDABLE', 'TOSUBCLASS', 'TOINSTANCE',
874 'TRANSLATABLE', 'PROPAGATED'],
875 ['VALUE', 'VALUE.ARRAY'])
876
877 a = attrs(tt)
878
879 q = CIMQualifier(a['NAME'], unpack_value(tt), type=a['TYPE'])
880
881
882 for i in ['OVERRIDABLE', 'TOSUBCLASS', 'TOINSTANCE',
883 'TRANSLATABLE', 'PROPAGATED']:
884 rv = a.get(i)
885 if rv not in ['true', 'false', None]:
886 raise ParseError("invalid value %s for %s on %s" %
887 (`rv`, i, name(tt)))
888 if rv == 'true':
889 rv = True
890 elif rv == 'false':
891 rv = False
892
893 setattr(q, i.lower(), rv)
894
895 return q
896
897
899 """Parse PROPERTY into a CIMProperty object.
900
901 VAL is just the pcdata of the enclosed VALUE node."""
902
903
904
905
906
907
908
909
910
911
912 check_node(tt, 'PROPERTY', ['TYPE', 'NAME'],
913 ['NAME', 'CLASSORIGIN', 'PROPAGATED', 'EmbeddedObject',
914 'EMBEDDEDOBJECT'],
915 ['QUALIFIER', 'VALUE'])
916
917 quals = {}
918 for q in list_of_matching(tt, ['QUALIFIER']):
919 quals[q.name] = q
920
921 a = attrs(tt)
922 try:
923 val = unpack_value(tt)
924 except ValueError as exc:
925 msg = str(exc)
926 raise ParseError('Cannot parse value for property "%s": %s' %\
927 (a['NAME'], msg))
928
929 embedded_object = None
930 if 'EmbeddedObject' in a or 'EMBEDDEDOBJECT' in a:
931 try:
932 embedded_object = a['EmbeddedObject']
933 except KeyError:
934 embedded_object = a['EMBEDDEDOBJECT']
935 if embedded_object is not None:
936 val = parse_embeddedObject(val)
937
938 return CIMProperty(a['NAME'],
939 val,
940 a['TYPE'],
941 class_origin=a.get('CLASSORIGIN'),
942 propagated=unpack_boolean(a.get('PROPAGATED')),
943 qualifiers=quals,
944 embedded_object=embedded_object)
945
946
948 """
949 <!ELEMENT PROPERTY.ARRAY (QUALIFIER*, VALUE.ARRAY?)>
950 <!ATTLIST PROPERTY.ARRAY %CIMName;
951 %CIMType; #REQUIRED
952 %ArraySize;
953 %ClassOrigin;
954 %Propagated;>
955 """
956
957 check_node(tt, 'PROPERTY.ARRAY', ['NAME', 'TYPE'],
958 ['REFERENCECLASS', 'CLASSORIGIN', 'PROPAGATED',
959 'ARRAYSIZE', 'EmbeddedObject', 'EMBEDDEDOBJECT'],
960 ['QUALIFIER', 'VALUE.ARRAY'])
961
962 quals = {}
963 for q in list_of_matching(tt, ['QUALIFIER']):
964 quals[q.name] = q
965
966 values = unpack_value(tt)
967 a = attrs(tt)
968 embedded_object = None
969 if 'EmbeddedObject' in a or 'EMBEDDEDOBJECT' in a:
970 try:
971 embedded_object = a['EmbeddedObject']
972 except KeyError:
973 embedded_object = a['EMBEDDEDOBJECT']
974
975 if embedded_object is not None:
976 values = parse_embeddedObject(values)
977
978 obj = CIMProperty(a['NAME'],
979 values,
980 a['TYPE'],
981 class_origin=a.get('CLASSORIGIN'),
982 qualifiers=quals,
983 is_array=True,
984 embedded_object=embedded_object)
985
986
987 return obj
988
989
991 """
992 <!ELEMENT PROPERTY.REFERENCE (QUALIFIER*, (VALUE.REFERENCE)?)>
993 <!ATTLIST PROPERTY.REFERENCE
994 %CIMName;
995 %ReferenceClass;
996 %ClassOrigin;
997 %Propagated;>
998 """
999
1000 check_node(tt, 'PROPERTY.REFERENCE', ['NAME'],
1001 ['REFERENCECLASS', 'CLASSORIGIN', 'PROPAGATED'])
1002
1003 value = list_of_matching(tt, ['VALUE.REFERENCE'])
1004
1005 if value is None or len(value) == 0:
1006 value = None
1007 elif len(value) == 1:
1008 value = value[0]
1009 else:
1010 raise ParseError('Too many VALUE.REFERENCE elements.')
1011
1012 attributes = attrs(tt)
1013 pref = CIMProperty(attributes['NAME'], value, type='reference')
1014
1015 for q in list_of_matching(tt, ['QUALIFIER']):
1016 pref.qualifiers[q.name] = q
1017
1018 if attributes.has_key('REFERENCECLASS'):
1019 pref.reference_class = attributes['REFERENCECLASS']
1020
1021 if attributes.has_key('CLASSORIGIN'):
1022 pref.class_origin = attributes['CLASSORIGIN']
1023
1024 if attributes.has_key('PROPAGATED'):
1025 pref.propagated = attributes['PROPAGATED']
1026
1027 return pref
1028
1029
1031 """
1032 <!ELEMENT METHOD (QUALIFIER*, (PARAMETER | PARAMETER.REFERENCE |
1033 PARAMETER.ARRAY | PARAMETER.REFARRAY)*)>
1034 <!ATTLIST METHOD %CIMName;
1035 %CIMType; #IMPLIED
1036 %ClassOrigin;
1037 %Propagated;>
1038 """
1039
1040 check_node(tt, 'METHOD', ['NAME'],
1041 ['TYPE', 'CLASSORIGIN', 'PROPAGATED'],
1042 ['QUALIFIER', 'PARAMETER', 'PARAMETER.REFERENCE',
1043 'PARAMETER.ARRAY', 'PARAMETER.REFARRAY'])
1044
1045 qualifiers = cim_obj.byname(list_of_matching(tt, ['QUALIFIER']))
1046
1047 parameters = cim_obj.byname(list_of_matching(tt, ['PARAMETER',
1048 'PARAMETER.REFERENCE',
1049 'PARAMETER.ARRAY',
1050 'PARAMETER.REFARRAY',]))
1051
1052 a = attrs(tt)
1053
1054 return CIMMethod(a['NAME'],
1055 return_type=a.get('TYPE'),
1056 parameters=parameters,
1057 qualifiers=qualifiers,
1058 class_origin=a.get('CLASSORIGIN'),
1059 propagated=unpack_boolean(a.get('PROPAGATED')))
1060
1061
1063 """
1064 <!ELEMENT PARAMETER (QUALIFIER*)>
1065 <!ATTLIST PARAMETER
1066 %CIMName;
1067 %CIMType; #REQUIRED>
1068 """
1069
1070 check_node(tt, 'PARAMETER', ['NAME', 'TYPE'], [])
1071
1072 quals = {}
1073 for q in list_of_matching(tt, ['QUALIFIER']):
1074 quals[q.name] = q
1075
1076 a = attrs(tt)
1077
1078 return CIMParameter(a['NAME'], type=a['TYPE'], qualifiers=quals)
1079
1081 """
1082 <!ELEMENT PARAMETER.REFERENCE (QUALIFIER*)>
1083 <!ATTLIST PARAMETER.REFERENCE
1084 %CIMName;
1085 %ReferenceClass;>
1086 """
1087
1088 check_node(tt, 'PARAMETER.REFERENCE', ['NAME'], ['REFERENCECLASS'])
1089
1090 quals = {}
1091 for q in list_of_matching(tt, ['QUALIFIER']):
1092 quals[q.name] = q
1093
1094 a = attrs(tt)
1095
1096 return CIMParameter(a['NAME'],
1097 type='reference',
1098 reference_class=a.get('REFERENCECLASS'),
1099 qualifiers=quals)
1100
1101
1103 """
1104 <!ELEMENT PARAMETER.ARRAY (QUALIFIER*)>
1105 <!ATTLIST PARAMETER.ARRAY
1106 %CIMName;
1107 %CIMType; #REQUIRED
1108 %ArraySize;>
1109 """
1110
1111 check_node(tt, 'PARAMETER.ARRAY', ['NAME', 'TYPE'],
1112 ['ARRAYSIZE'])
1113
1114 quals = {}
1115 for q in list_of_matching(tt, ['QUALIFIER']):
1116 quals[q.name] = q
1117
1118 a = attrs(tt)
1119
1120 array_size = a.get('ARRAYSIZE')
1121 if array_size is not None:
1122 array_size = int(array_size)
1123
1124 return CIMParameter(a['NAME'],
1125 type=a['TYPE'],
1126 is_array=True,
1127 array_size=array_size,
1128 qualifiers=quals)
1129
1130
1132 """
1133 <!ELEMENT PARAMETER.REFARRAY (QUALIFIER*)>
1134 <!ATTLIST PARAMETER.REFARRAY
1135 %CIMName;
1136 %ReferenceClass;
1137 %ArraySize;>
1138 """
1139
1140 check_node(tt, 'PARAMETER.REFARRAY', ['NAME'],
1141 ['REFERENCECLASS', 'ARRAYSIZE'])
1142
1143 quals = {}
1144 for q in list_of_matching(tt, ['QUALIFIER']):
1145 quals[q.name] = q
1146
1147 a = attrs(tt)
1148
1149 array_size = a.get('ARRAYSIZE')
1150 if array_size is not None:
1151 array_size = int(array_size)
1152
1153 return CIMParameter(a['NAME'], 'reference',
1154 is_array=True,
1155 reference_class=a.get('REFERENCECLASS'),
1156 array_size=array_size,
1157 qualifiers=quals)
1158
1159
1160
1161
1162
1163
1165 """
1166 <!ELEMENT MESSAGE (SIMPLEREQ | MULTIREQ | SIMPLERSP | MULTIRSP)>
1167 <!ATTLIST MESSAGE
1168 ID CDATA #REQUIRED
1169 PROTOCOLVERSION CDATA #REQUIRED>
1170 """
1171
1172 check_node(tt, 'MESSAGE', ['ID', 'PROTOCOLVERSION'])
1173
1174 messages = one_child(
1175 tt, ['SIMPLEREQ', 'MULTIREQ', 'SIMPLERSP', 'MULTIRSP', 'SIMPLEEXPREQ'])
1176
1177 if type(messages) is not list:
1178
1179 messages = [messages]
1180
1181 return name(tt), attrs(tt), messages
1182
1183
1185 raise ParseError('MULTIREQ parser not implemented')
1186
1187
1189 raise ParseError('MULTIEXPREQ parser not implemented')
1190
1192 """
1193 <!ELEMENT SIMPLEEXPREQ (EXPMETHODCALL)>
1194 """
1195
1196 child = one_child(tt, ['EXPMETHODCALL'])
1197
1198 return name(tt), attrs(tt), child
1199
1201 """
1202 <!ELEMENT SIMPLEREQ (IMETHODCALL | METHODCALL)>
1203 """
1204
1205 check_node(tt, 'SIMPLEREQ')
1206
1207 child = one_child(tt, ['IMETHODCALL', 'METHODCALL'])
1208
1209 return name(tt), attrs(tt), child
1210
1211
1213 """
1214 <!ELEMENT IMETHODCALL (LOCALNAMESPACEPATH, IPARAMVALUE*)>
1215 <!ATTLIST IMETHODCALL
1216 %CIMName;>
1217 """
1218
1219 check_node(tt, 'IMETHODCALL', ['NAME'])
1220
1221 if len(kids(tt)) < 1:
1222 raise ParseError('Expecting LOCALNAMESPACEPATH, got nothing')
1223
1224 localnspath = parse_localnamespacepath(kids(tt)[0])
1225
1226 params = map(lambda x: parse_iparamvalue(x),
1227 kids(tt)[1:])
1228
1229 return (name(tt), attrs(tt), localnspath, params)
1230
1231
1233 """
1234 <!ELEMENT METHODCALL ((LOCALCLASSPATH|LOCALINSTANCEPATH),PARAMVALUE*)>
1235 <!ATTLIST METHODCALL
1236 %CIMName;>
1237 """
1238
1239 check_node(tt, 'METHODCALL', ['NAME'], [],
1240 ['LOCALCLASSPATH', 'LOCALINSTANCEPATH', 'PARAMVALUE'])
1241 path = list_of_matching(tt, ['LOCALCLASSPATH', 'LOCALINSTANCEPATH'])
1242 if len(path) != 1:
1243 raise ParseError('Expecting one of LOCALCLASSPATH or ' \
1244 'LOCALINSTANCEPATH, got %s' % `path`)
1245 path = path[0]
1246 params = list_of_matching(tt, ['PARAMVALUE'])
1247 return (name(tt), attrs(tt), path, params)
1248
1249
1251 """
1252 <!ELEMENT EXPMETHODCALL (EXPPARAMVALUE*)>
1253 <!ATTLIST EXPMETHODCALL
1254 %CIMName;>
1255 """
1256
1257 check_node(tt, 'EXPMETHODCALL', ['NAME'], [], ['EXPPARAMVALUE'])
1258
1259
1260 params = list_of_matching(tt, ['EXPPARAMVALUE'])
1261
1262 return (name(tt), attrs(tt), params)
1263
1264
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277 check_node(tt, 'PARAMVALUE', ['NAME'],
1278 ['PARAMTYPE', 'EmbeddedObject', 'EMBEDDEDOBJECT'])
1279
1280 child = optional_child(tt,
1281 ['VALUE', 'VALUE.REFERENCE', 'VALUE.ARRAY',
1282 'VALUE.REFARRAY',])
1283
1284 if attrs(tt).has_key('PARAMTYPE'):
1285 paramtype = attrs(tt)['PARAMTYPE']
1286 else:
1287 paramtype = None
1288
1289 if 'EmbeddedObject' in attrs(tt) or 'EMBEDDEDOBJECT' in attrs(tt):
1290 child = parse_embeddedObject(child)
1291
1292 return attrs(tt)['NAME'], paramtype, child
1293
1294
1296
1297
1298
1299
1300
1301 """Returns NAME, VALUE pair."""
1302
1303 check_node(tt, 'IPARAMVALUE', ['NAME'], [])
1304
1305 child = optional_child(tt,
1306 ['VALUE', 'VALUE.ARRAY', 'VALUE.REFERENCE',
1307 'INSTANCENAME', 'CLASSNAME',
1308 'QUALIFIER.DECLARATION', 'CLASS', 'INSTANCE',
1309 'VALUE.NAMEDINSTANCE'])
1310
1311 name = attrs(tt)['NAME']
1312 if isinstance(child, basestring) and \
1313 name.lower() in ['deepinheritance', 'localonly',
1314 'includequalifiers', 'includeclassorigin']:
1315 if child.lower() in ['true', 'false']:
1316 child = child.lower() == 'true'
1317
1318 return name, child
1319
1320
1322 """
1323 <!ELEMENT EXPPARAMVALUE (INSTANCE?)>
1324 <!ATTLIST EXPPARAMVALUE
1325 %CIMName;>
1326 """
1327
1328 check_node(tt, 'EXPPARAMVALUE', ['NAME'], [], ['INSTANCE'])
1329
1330 child = optional_child(tt, ['INSTANCE'])
1331
1332 name = attrs(tt)['NAME']
1333 return name, child
1334
1335
1337 raise ParseError('MULTIRSP parser not implemented')
1338
1339
1341 raise ParseError('MULTIEXPRSP parser not implemented')
1342
1343
1345
1346 check_node(tt, 'SIMPLERSP', [], [])
1347
1348 child = one_child(tt, ['METHODRESPONSE', 'IMETHODRESPONSE'])
1349
1350 return name(tt), attrs(tt), child
1351
1352
1354 raise ParseError('SIMPLEEXPRSP parser not implemented')
1355
1356
1358
1359
1360
1361
1362 check_node(tt, 'METHODRESPONSE', ['NAME'], [])
1363
1364 return name(tt), attrs(tt), list_of_various(tt, ['ERROR', 'RETURNVALUE',
1365 'PARAMVALUE'])
1366
1367
1369 raise ParseError('EXPMETHODRESPONSE parser not implemented')
1370
1371
1373
1374
1375 check_node(tt, 'IMETHODRESPONSE', ['NAME'], [])
1376
1377 return name(tt), attrs(tt), optional_child(tt, ['ERROR', 'IRETURNVALUE'])
1378
1379
1381 """
1382 <!ELEMENT ERROR EMPTY>
1383 <!ATTLIST ERROR
1384 CODE CDATA #REQUIRED
1385 DESCRIPTION CDATA #IMPLIED>
1386 """
1387
1388
1389
1390 check_node(tt, 'ERROR', ['CODE'], ['DESCRIPTION'])
1391
1392 return (name(tt), attrs(tt), None)
1393
1394
1396
1397
1398
1399
1400
1401
1402
1403
1404 check_node(tt, 'RETURNVALUE', [], ['PARAMTYPE'])
1405
1406 return name(tt), attrs(tt), one_child(tt, ['VALUE', 'VALUE.ARRAY',
1407 'VALUE.REFERENCE',
1408 'VALUE.REFARRAY'])
1409
1410
1412
1413
1414
1415
1416
1417
1418
1419 check_node(tt, 'IRETURNVALUE', [], [])
1420
1421
1422
1423
1424
1425 values = list_of_same(tt, ['CLASSNAME', 'INSTANCENAME',
1426 'VALUE', 'VALUE.OBJECTWITHPATH', 'VALUE.OBJECT',
1427 'OBJECTPATH', 'QUALIFIER.DECLARATION',
1428 'VALUE.ARRAY', 'VALUE.REFERENCE',
1429 'CLASS', 'INSTANCE',
1430 'VALUE.NAMEDINSTANCE',])
1431
1432
1433
1434 return name(tt), attrs(tt), values
1435
1436
1437
1438
1439
1441 """Parse any fragment of XML."""
1442
1443 nodename = name(tt).lower().replace('.', '_')
1444 fn_name = 'parse_' + nodename
1445 fn = globals().get(fn_name)
1446 if fn is None:
1447 raise ParseError('no parser for node type %s' % name(tt))
1448 else:
1449 return fn(tt)
1450
1452 if isinstance(val, list):
1453 return [parse_embeddedObject(obj) for obj in val]
1454 if val is None:
1455 return None
1456 tt = tupletree.xml_to_tupletree(val)
1457 if tt[0] == 'INSTANCE':
1458 return parse_instance(tt)
1459 elif tt[0] == 'CLASS':
1460 return parse_class(tt)
1461 else:
1462 raise ParseError('Error parsing embedded object')
1463
1464
1466 """Find VALUE or VALUE.ARRAY under TT and convert to a Python value.
1467
1468 Looks at the TYPE of the node to work out how to decode it.
1469 Handles nodes with no value (e.g. in CLASS.)
1470 """
1471
1472
1473 valtype = attrs(tt)['TYPE']
1474
1475 raw_val = list_of_matching(tt, ['VALUE', 'VALUE.ARRAY'])
1476 if len(raw_val) == 0:
1477 return None
1478 elif len(raw_val) > 1:
1479 raise ParseError('more than one VALUE or VALUE.ARRAY under %s' % \
1480 name(tt))
1481
1482 raw_val = raw_val[0]
1483
1484 if isinstance(raw_val, list):
1485 return [cim_obj.tocimobj(valtype, x) for x in raw_val]
1486 elif len(raw_val) == 0 and valtype != 'string':
1487 return None
1488 else:
1489 return cim_obj.tocimobj(valtype, raw_val)
1490
1491
1493 """Unpack a boolean, represented as "TRUE" or "FALSE" in CIM."""
1494 if p is None:
1495 return None
1496
1497
1498
1499
1500 p = p.strip().lower()
1501 if p == 'true':
1502 return True
1503 elif p == 'false':
1504 return False
1505 elif p == '':
1506 return None
1507 else:
1508 raise ParseError('invalid boolean %s' % `p`)
1509