xref: /aoo41x/main/configmgr/source/xcsparser.cxx (revision cdf0e10c)
1 /*************************************************************************
2 *
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
6 *
7 * OpenOffice.org - a multi-platform office productivity suite
8 *
9 * This file is part of OpenOffice.org.
10 *
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
14 *
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
20 *
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org.  If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
25 *
26 ************************************************************************/
27 
28 #include "precompiled_configmgr.hxx"
29 #include "sal/config.h"
30 
31 #include <cstddef>
32 
33 #include "com/sun/star/uno/Any.hxx"
34 #include "com/sun/star/uno/Reference.hxx"
35 #include "com/sun/star/uno/RuntimeException.hpp"
36 #include "com/sun/star/uno/XInterface.hpp"
37 #include "osl/diagnose.h"
38 #include "rtl/ref.hxx"
39 #include "rtl/strbuf.hxx"
40 #include "rtl/string.h"
41 #include "rtl/string.hxx"
42 #include "rtl/ustring.h"
43 #include "rtl/ustring.hxx"
44 #include "xmlreader/span.hxx"
45 #include "xmlreader/xmlreader.hxx"
46 
47 #include "data.hxx"
48 #include "localizedpropertynode.hxx"
49 #include "groupnode.hxx"
50 #include "node.hxx"
51 #include "nodemap.hxx"
52 #include "parsemanager.hxx"
53 #include "propertynode.hxx"
54 #include "setnode.hxx"
55 #include "xcsparser.hxx"
56 #include "xmldata.hxx"
57 
58 namespace configmgr {
59 
60 namespace {
61 
62 namespace css = com::sun::star;
63 
64 // Conservatively merge a template or component (and its recursive parts) into
65 // an existing instance:
66 void merge(
67     rtl::Reference< Node > const & original,
68     rtl::Reference< Node > const & update)
69 {
70     OSL_ASSERT(
71         original.is() && update.is() && original->kind() == update->kind() &&
72         update->getFinalized() == Data::NO_LAYER);
73     if (update->getLayer() >= original->getLayer() &&
74         update->getLayer() <= original->getFinalized())
75     {
76         switch (original->kind()) {
77         case Node::KIND_PROPERTY:
78         case Node::KIND_LOCALIZED_PROPERTY:
79         case Node::KIND_LOCALIZED_VALUE:
80             break; //TODO: merge certain parts?
81         case Node::KIND_GROUP:
82             for (NodeMap::iterator i2(update->getMembers().begin());
83                  i2 != update->getMembers().end(); ++i2)
84             {
85                 NodeMap::iterator i1(original->getMembers().find(i2->first));
86                 if (i1 == original->getMembers().end()) {
87                     if (i2->second->kind() == Node::KIND_PROPERTY &&
88                         dynamic_cast< GroupNode * >(
89                             original.get())->isExtensible())
90                     {
91                         original->getMembers().insert(*i2);
92                     }
93                 } else if (i2->second->kind() == i1->second->kind()) {
94                     merge(i1->second, i2->second);
95                 }
96             }
97             break;
98         case Node::KIND_SET:
99             for (NodeMap::iterator i2(update->getMembers().begin());
100                  i2 != update->getMembers().end(); ++i2)
101             {
102                 NodeMap::iterator i1(original->getMembers().find(i2->first));
103                 if (i1 == original->getMembers().end()) {
104                     if (dynamic_cast< SetNode * >(original.get())->
105                         isValidTemplate(i2->second->getTemplateName()))
106                     {
107                         original->getMembers().insert(*i2);
108                     }
109                 } else if (i2->second->kind() == i1->second->kind() &&
110                            (i2->second->getTemplateName() ==
111                             i1->second->getTemplateName()))
112                 {
113                     merge(i1->second, i2->second);
114                 }
115             }
116             break;
117         }
118     }
119 }
120 
121 }
122 
123 XcsParser::XcsParser(int layer, Data & data):
124     valueParser_(layer), data_(data), state_(STATE_START)
125 {}
126 
127 XcsParser::~XcsParser() {}
128 
129 xmlreader::XmlReader::Text XcsParser::getTextMode() {
130     return valueParser_.getTextMode();
131 }
132 
133 bool XcsParser::startElement(
134     xmlreader::XmlReader & reader, int nsId, xmlreader::Span const & name)
135 {
136     if (valueParser_.startElement(reader, nsId, name)) {
137         return true;
138     }
139     if (state_ == STATE_START) {
140         if (nsId == ParseManager::NAMESPACE_OOR &&
141             name.equals(RTL_CONSTASCII_STRINGPARAM("component-schema"))) {
142             handleComponentSchema(reader);
143             state_ = STATE_COMPONENT_SCHEMA;
144             ignoring_ = 0;
145             return true;
146         }
147     } else {
148         //TODO: ignoring component-schema import, component-schema uses, and
149         // prop constraints; accepting all four at illegal places (and with
150         // illegal content):
151         if (ignoring_ > 0 ||
152             (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
153              (name.equals(RTL_CONSTASCII_STRINGPARAM("info")) ||
154               name.equals(RTL_CONSTASCII_STRINGPARAM("import")) ||
155               name.equals(RTL_CONSTASCII_STRINGPARAM("uses")) ||
156               name.equals(RTL_CONSTASCII_STRINGPARAM("constraints")))))
157         {
158             OSL_ASSERT(ignoring_ < LONG_MAX);
159             ++ignoring_;
160             return true;
161         }
162         switch (state_) {
163         case STATE_COMPONENT_SCHEMA:
164             if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
165                 name.equals(RTL_CONSTASCII_STRINGPARAM("templates")))
166             {
167                 state_ = STATE_TEMPLATES;
168                 return true;
169             }
170             // fall through
171         case STATE_TEMPLATES_DONE:
172             if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
173                 name.equals(RTL_CONSTASCII_STRINGPARAM("component")))
174             {
175                 state_ = STATE_COMPONENT;
176                 OSL_ASSERT(elements_.empty());
177                 elements_.push(
178                     Element(
179                         new GroupNode(
180                             valueParser_.getLayer(), false, rtl::OUString()),
181                         componentName_));
182                 return true;
183             }
184             break;
185         case STATE_TEMPLATES:
186             if (elements_.empty()) {
187                 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
188                     name.equals(RTL_CONSTASCII_STRINGPARAM("group")))
189                 {
190                     handleGroup(reader, true);
191                     return true;
192                 }
193                 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
194                     name.equals(RTL_CONSTASCII_STRINGPARAM("set")))
195                 {
196                     handleSet(reader, true);
197                     return true;
198                 }
199                 break;
200             }
201             // fall through
202         case STATE_COMPONENT:
203             OSL_ASSERT(!elements_.empty());
204             switch (elements_.top().node->kind()) {
205             case Node::KIND_PROPERTY:
206             case Node::KIND_LOCALIZED_PROPERTY:
207                 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
208                     name.equals(RTL_CONSTASCII_STRINGPARAM("value")))
209                 {
210                     handlePropValue(reader, elements_.top().node);
211                     return true;
212                 }
213                 break;
214             case Node::KIND_GROUP:
215                 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
216                     name.equals(RTL_CONSTASCII_STRINGPARAM("prop")))
217                 {
218                     handleProp(reader);
219                     return true;
220                 }
221                 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
222                     name.equals(RTL_CONSTASCII_STRINGPARAM("node-ref")))
223                 {
224                     handleNodeRef(reader);
225                     return true;
226                 }
227                 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
228                     name.equals(RTL_CONSTASCII_STRINGPARAM("group")))
229                 {
230                     handleGroup(reader, false);
231                     return true;
232                 }
233                 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
234                     name.equals(RTL_CONSTASCII_STRINGPARAM("set")))
235                 {
236                     handleSet(reader, false);
237                     return true;
238                 }
239                 break;
240             case Node::KIND_SET:
241                 if (nsId == xmlreader::XmlReader::NAMESPACE_NONE &&
242                     name.equals(RTL_CONSTASCII_STRINGPARAM("item")))
243                 {
244                     handleSetItem(
245                         reader,
246                         dynamic_cast< SetNode * >(elements_.top().node.get()));
247                     return true;
248                 }
249                 break;
250             default: // Node::KIND_LOCALIZED_VALUE
251                 OSL_ASSERT(false); // this cannot happen
252                 break;
253             }
254             break;
255         case STATE_COMPONENT_DONE:
256             break;
257         default: // STATE_START
258             OSL_ASSERT(false); // this cannot happen
259             break;
260         }
261     }
262     throw css::uno::RuntimeException(
263         (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("bad member <")) +
264          name.convertFromUtf8() +
265          rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("> in ")) + reader.getUrl()),
266         css::uno::Reference< css::uno::XInterface >());
267 }
268 
269 void XcsParser::endElement(xmlreader::XmlReader const & reader) {
270     if (valueParser_.endElement()) {
271         return;
272     }
273     if (ignoring_ > 0) {
274         --ignoring_;
275     } else if (!elements_.empty()) {
276         Element top(elements_.top());
277         elements_.pop();
278         if (top.node.is()) {
279             if (elements_.empty()) {
280                 switch (state_) {
281                 case STATE_TEMPLATES:
282                     {
283                         NodeMap::iterator i(data_.templates.find(top.name));
284                         if (i == data_.templates.end()) {
285                             data_.templates.insert(
286                                 NodeMap::value_type(top.name, top.node));
287                         } else {
288                             merge(i->second, top.node);
289                         }
290                     }
291                     break;
292                 case STATE_COMPONENT:
293                     {
294                         NodeMap::iterator i(data_.components.find(top.name));
295                         if (i == data_.components.end()) {
296                             data_.components.insert(
297                                 NodeMap::value_type(top.name, top.node));
298                         } else {
299                             merge(i->second, top.node);
300                         }
301                         state_ = STATE_COMPONENT_DONE;
302                     }
303                     break;
304                 default:
305                     OSL_ASSERT(false);
306                     throw css::uno::RuntimeException(
307                         rtl::OUString(
308                             RTL_CONSTASCII_USTRINGPARAM("this cannot happen")),
309                         css::uno::Reference< css::uno::XInterface >());
310                 }
311             } else if (!elements_.top().node->getMembers().insert(
312                            NodeMap::value_type(top.name, top.node)).second)
313             {
314                 throw css::uno::RuntimeException(
315                     (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("duplicate ")) +
316                      top.name +
317                      rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
318                      reader.getUrl()),
319                     css::uno::Reference< css::uno::XInterface >());
320             }
321         }
322     } else {
323         switch (state_) {
324         case STATE_COMPONENT_SCHEMA:
325             // To support old, broken extensions with .xcs files that contain
326             // empty <component-schema> elements:
327             state_ = STATE_COMPONENT_DONE;
328             break;
329         case STATE_TEMPLATES:
330             state_ = STATE_TEMPLATES_DONE;
331             break;
332         case STATE_TEMPLATES_DONE:
333             throw css::uno::RuntimeException(
334                 (rtl::OUString(
335                     RTL_CONSTASCII_USTRINGPARAM("no component element in ")) +
336                  reader.getUrl()),
337                 css::uno::Reference< css::uno::XInterface >());
338         case STATE_COMPONENT_DONE:
339             break;
340         default:
341             OSL_ASSERT(false); // this cannot happen
342         }
343     }
344 }
345 
346 void XcsParser::characters(xmlreader::Span const & text) {
347     valueParser_.characters(text);
348 }
349 
350 void XcsParser::handleComponentSchema(xmlreader::XmlReader & reader) {
351     //TODO: oor:version, xml:lang attributes
352     rtl::OStringBuffer buf;
353     buf.append('.');
354     bool hasPackage = false;
355     bool hasName = false;
356     for (;;) {
357         int attrNsId;
358         xmlreader::Span attrLn;
359         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
360             break;
361         }
362         if (attrNsId == ParseManager::NAMESPACE_OOR &&
363             attrLn.equals(RTL_CONSTASCII_STRINGPARAM("package")))
364         {
365             if (hasPackage) {
366                 throw css::uno::RuntimeException(
367                     (rtl::OUString(
368                         RTL_CONSTASCII_USTRINGPARAM(
369                             "multiple component-schema package attributes"
370                             " in ")) +
371                      reader.getUrl()),
372                     css::uno::Reference< css::uno::XInterface >());
373             }
374             hasPackage = true;
375             xmlreader::Span s(reader.getAttributeValue(false));
376             buf.insert(0, s.begin, s.length);
377         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
378                    attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
379         {
380             if (hasName) {
381                 throw css::uno::RuntimeException(
382                     (rtl::OUString(
383                         RTL_CONSTASCII_USTRINGPARAM(
384                             "multiple component-schema name attributes in ")) +
385                      reader.getUrl()),
386                     css::uno::Reference< css::uno::XInterface >());
387             }
388             hasName = true;
389             xmlreader::Span s(reader.getAttributeValue(false));
390             buf.append(s.begin, s.length);
391         }
392     }
393     if (!hasPackage) {
394         throw css::uno::RuntimeException(
395             (rtl::OUString(
396                 RTL_CONSTASCII_USTRINGPARAM(
397                     "no component-schema package attribute in ")) +
398              reader.getUrl()),
399             css::uno::Reference< css::uno::XInterface >());
400     }
401     if (!hasName) {
402         throw css::uno::RuntimeException(
403             (rtl::OUString(
404                 RTL_CONSTASCII_USTRINGPARAM(
405                     "no component-schema name attribute in ")) +
406              reader.getUrl()),
407             css::uno::Reference< css::uno::XInterface >());
408     }
409     componentName_ = xmlreader::Span(buf.getStr(), buf.getLength()).
410         convertFromUtf8();
411 }
412 
413 void XcsParser::handleNodeRef(xmlreader::XmlReader & reader) {
414     bool hasName = false;
415     rtl::OUString name;
416     rtl::OUString component(componentName_);
417     bool hasNodeType = false;
418     rtl::OUString nodeType;
419     for (;;) {
420         int attrNsId;
421         xmlreader::Span attrLn;
422         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
423             break;
424         }
425         if (attrNsId == ParseManager::NAMESPACE_OOR &&
426             attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
427         {
428             hasName = true;
429             name = reader.getAttributeValue(false).convertFromUtf8();
430         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
431                    attrLn.equals(RTL_CONSTASCII_STRINGPARAM("component")))
432         {
433             component = reader.getAttributeValue(false).convertFromUtf8();
434         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
435                    attrLn.equals(RTL_CONSTASCII_STRINGPARAM("node-type")))
436         {
437             hasNodeType = true;
438             nodeType = reader.getAttributeValue(false).convertFromUtf8();
439         }
440     }
441     if (!hasName) {
442         throw css::uno::RuntimeException(
443             (rtl::OUString(
444                 RTL_CONSTASCII_USTRINGPARAM("no node-ref name attribute in ")) +
445              reader.getUrl()),
446             css::uno::Reference< css::uno::XInterface >());
447     }
448     rtl::Reference< Node > tmpl(
449         data_.getTemplate(
450             valueParser_.getLayer(),
451             xmldata::parseTemplateReference(
452                 component, hasNodeType, nodeType, 0)));
453     if (!tmpl.is()) {
454         //TODO: this can erroneously happen as long as import/uses attributes
455         // are not correctly processed
456         throw css::uno::RuntimeException(
457             (rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("unknown node-ref ")) +
458              name + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(" in ")) +
459              reader.getUrl()),
460             css::uno::Reference< css::uno::XInterface >());
461     }
462     rtl::Reference< Node > node(tmpl->clone(false));
463     node->setLayer(valueParser_.getLayer());
464     elements_.push(Element(node, name));
465 }
466 
467 void XcsParser::handleProp(xmlreader::XmlReader & reader) {
468     bool hasName = false;
469     rtl::OUString name;
470     valueParser_.type_ = TYPE_ERROR;
471     bool localized = false;
472     bool nillable = true;
473     for (;;) {
474         int attrNsId;
475         xmlreader::Span attrLn;
476         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
477             break;
478         }
479         if (attrNsId == ParseManager::NAMESPACE_OOR &&
480             attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
481         {
482             hasName = true;
483             name = reader.getAttributeValue(false).convertFromUtf8();
484         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
485                    attrLn.equals(RTL_CONSTASCII_STRINGPARAM("type")))
486         {
487             valueParser_.type_ = xmldata::parseType(
488                 reader, reader.getAttributeValue(true));
489         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
490                    attrLn.equals(RTL_CONSTASCII_STRINGPARAM("localized")))
491         {
492             localized = xmldata::parseBoolean(reader.getAttributeValue(true));
493         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
494                    attrLn.equals(RTL_CONSTASCII_STRINGPARAM("nillable")))
495         {
496             nillable = xmldata::parseBoolean(reader.getAttributeValue(true));
497         }
498     }
499     if (!hasName) {
500         throw css::uno::RuntimeException(
501             (rtl::OUString(
502                 RTL_CONSTASCII_USTRINGPARAM("no prop name attribute in ")) +
503              reader.getUrl()),
504             css::uno::Reference< css::uno::XInterface >());
505     }
506     if (valueParser_.type_ == TYPE_ERROR) {
507         throw css::uno::RuntimeException(
508             (rtl::OUString(
509                 RTL_CONSTASCII_USTRINGPARAM("no prop type attribute in ")) +
510              reader.getUrl()),
511             css::uno::Reference< css::uno::XInterface >());
512     }
513     elements_.push(
514         Element(
515             (localized
516              ? rtl::Reference< Node >(
517                  new LocalizedPropertyNode(
518                      valueParser_.getLayer(), valueParser_.type_, nillable))
519              : rtl::Reference< Node >(
520                  new PropertyNode(
521                      valueParser_.getLayer(), valueParser_.type_, nillable,
522                      css::uno::Any(), false))),
523             name));
524 }
525 
526 void XcsParser::handlePropValue(
527     xmlreader::XmlReader & reader, rtl::Reference< Node > const & property)
528 {
529     xmlreader::Span attrSeparator;
530     for (;;) {
531         int attrNsId;
532         xmlreader::Span attrLn;
533         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
534             break;
535         }
536         if (attrNsId == ParseManager::NAMESPACE_OOR &&
537             attrLn.equals(RTL_CONSTASCII_STRINGPARAM("separator")))
538         {
539             attrSeparator = reader.getAttributeValue(false);
540             if (attrSeparator.length == 0) {
541                 throw css::uno::RuntimeException(
542                     (rtl::OUString(
543                         RTL_CONSTASCII_USTRINGPARAM(
544                             "bad oor:separator attribute in ")) +
545                      reader.getUrl()),
546                     css::uno::Reference< css::uno::XInterface >());
547             }
548         }
549     }
550     valueParser_.separator_ = rtl::OString(
551         attrSeparator.begin, attrSeparator.length);
552     valueParser_.start(property);
553 }
554 
555 void XcsParser::handleGroup(xmlreader::XmlReader & reader, bool isTemplate) {
556     bool hasName = false;
557     rtl::OUString name;
558     bool extensible = false;
559     for (;;) {
560         int attrNsId;
561         xmlreader::Span attrLn;
562         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
563             break;
564         }
565         if (attrNsId == ParseManager::NAMESPACE_OOR &&
566             attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
567         {
568             hasName = true;
569             name = reader.getAttributeValue(false).convertFromUtf8();
570         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
571                    attrLn.equals(RTL_CONSTASCII_STRINGPARAM("extensible")))
572         {
573             extensible = xmldata::parseBoolean(reader.getAttributeValue(true));
574         }
575     }
576     if (!hasName) {
577         throw css::uno::RuntimeException(
578             (rtl::OUString(
579                 RTL_CONSTASCII_USTRINGPARAM("no group name attribute in ")) +
580              reader.getUrl()),
581             css::uno::Reference< css::uno::XInterface >());
582     }
583     if (isTemplate) {
584         name = Data::fullTemplateName(componentName_, name);
585     }
586     elements_.push(
587         Element(
588             new GroupNode(
589                 valueParser_.getLayer(), extensible,
590                 isTemplate ? name : rtl::OUString()),
591             name));
592 }
593 
594 void XcsParser::handleSet(xmlreader::XmlReader & reader, bool isTemplate) {
595     bool hasName = false;
596     rtl::OUString name;
597     rtl::OUString component(componentName_);
598     bool hasNodeType = false;
599     rtl::OUString nodeType;
600     for (;;) {
601         int attrNsId;
602         xmlreader::Span attrLn;
603         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
604             break;
605         }
606         if (attrNsId == ParseManager::NAMESPACE_OOR &&
607             attrLn.equals(RTL_CONSTASCII_STRINGPARAM("name")))
608         {
609             hasName = true;
610             name = reader.getAttributeValue(false).convertFromUtf8();
611         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
612                    attrLn.equals(RTL_CONSTASCII_STRINGPARAM("component")))
613         {
614             component = reader.getAttributeValue(false).convertFromUtf8();
615         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
616                    attrLn.equals(RTL_CONSTASCII_STRINGPARAM("node-type")))
617         {
618             hasNodeType = true;
619             nodeType = reader.getAttributeValue(false).convertFromUtf8();
620         }
621     }
622     if (!hasName) {
623         throw css::uno::RuntimeException(
624             (rtl::OUString(
625                 RTL_CONSTASCII_USTRINGPARAM("no set name attribute in ")) +
626              reader.getUrl()),
627             css::uno::Reference< css::uno::XInterface >());
628     }
629     if (isTemplate) {
630         name = Data::fullTemplateName(componentName_, name);
631     }
632     elements_.push(
633         Element(
634             new SetNode(
635                 valueParser_.getLayer(),
636                 xmldata::parseTemplateReference(
637                     component, hasNodeType, nodeType, 0),
638                 isTemplate ? name : rtl::OUString()),
639             name));
640 }
641 
642 void XcsParser::handleSetItem(xmlreader::XmlReader & reader, SetNode * set) {
643     rtl::OUString component(componentName_);
644     bool hasNodeType = false;
645     rtl::OUString nodeType;
646     for (;;) {
647         int attrNsId;
648         xmlreader::Span attrLn;
649         if (!reader.nextAttribute(&attrNsId, &attrLn)) {
650             break;
651         }
652         if (attrNsId == ParseManager::NAMESPACE_OOR &&
653             attrLn.equals(RTL_CONSTASCII_STRINGPARAM("component")))
654         {
655             component = reader.getAttributeValue(false).convertFromUtf8();
656         } else if (attrNsId == ParseManager::NAMESPACE_OOR &&
657                    attrLn.equals(RTL_CONSTASCII_STRINGPARAM("node-type")))
658         {
659             hasNodeType = true;
660             nodeType = reader.getAttributeValue(false).convertFromUtf8();
661         }
662     }
663     set->getAdditionalTemplateNames().push_back(
664         xmldata::parseTemplateReference(component, hasNodeType, nodeType, 0));
665     elements_.push(Element(rtl::Reference< Node >(), rtl::OUString()));
666 }
667 
668 }
669