1//
2// XMLConfiguration.cpp
3//
4// Library: Util
5// Package: Configuration
6// Module: XMLConfiguration
7//
8// Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Util/XMLConfiguration.h"
16
17
18#ifndef POCO_UTIL_NO_XMLCONFIGURATION
19
20
21#include "Poco/SAX/InputSource.h"
22#include "Poco/DOM/DOMParser.h"
23#include "Poco/DOM/Element.h"
24#include "Poco/DOM/Attr.h"
25#include "Poco/DOM/Text.h"
26#include "Poco/XML/XMLWriter.h"
27#include "Poco/Exception.h"
28#include "Poco/NumberParser.h"
29#include "Poco/NumberFormatter.h"
30#include <set>
31
32
33namespace Poco {
34namespace Util {
35
36
37XMLConfiguration::XMLConfiguration():
38 _delim('.')
39{
40 loadEmpty("config");
41}
42
43
44XMLConfiguration::XMLConfiguration(char delim):
45 _delim(delim)
46{
47 loadEmpty("config");
48}
49
50
51XMLConfiguration::XMLConfiguration(Poco::XML::InputSource* pInputSource):
52 _delim('.')
53{
54 load(pInputSource);
55}
56
57
58XMLConfiguration::XMLConfiguration(Poco::XML::InputSource* pInputSource, char delim):
59 _delim(delim)
60{
61 load(pInputSource);
62}
63
64
65XMLConfiguration::XMLConfiguration(std::istream& istr):
66 _delim('.')
67{
68 load(istr);
69}
70
71
72XMLConfiguration::XMLConfiguration(std::istream& istr, char delim):
73 _delim(delim)
74{
75 load(istr);
76}
77
78
79XMLConfiguration::XMLConfiguration(const std::string& path):
80 _delim('.')
81{
82 load(path);
83}
84
85
86XMLConfiguration::XMLConfiguration(const std::string& path, char delim):
87 _delim(delim)
88{
89 load(path);
90}
91
92
93XMLConfiguration::XMLConfiguration(const Poco::XML::Document* pDocument):
94 _delim('.')
95{
96 load(pDocument);
97}
98
99
100XMLConfiguration::XMLConfiguration(const Poco::XML::Document* pDocument, char delim):
101 _delim(delim)
102{
103 load(pDocument);
104}
105
106
107XMLConfiguration::XMLConfiguration(const Poco::XML::Node* pNode):
108 _delim('.')
109{
110 load(pNode);
111}
112
113
114XMLConfiguration::XMLConfiguration(const Poco::XML::Node* pNode, char delim):
115 _delim(delim)
116{
117 load(pNode);
118}
119
120
121XMLConfiguration::~XMLConfiguration()
122{
123}
124
125
126void XMLConfiguration::load(Poco::XML::InputSource* pInputSource, unsigned long namePoolSize)
127{
128 poco_check_ptr (pInputSource);
129
130 Poco::XML::DOMParser parser(namePoolSize);
131 parser.setFeature(Poco::XML::XMLReader::FEATURE_NAMESPACES, false);
132 parser.setFeature(Poco::XML::DOMParser::FEATURE_FILTER_WHITESPACE, true);
133 Poco::XML::AutoPtr<Poco::XML::Document> pDoc = parser.parse(pInputSource);
134 load(pDoc);
135}
136
137
138void XMLConfiguration::load(Poco::XML::InputSource* pInputSource)
139{
140 load(pInputSource, POCO_XML_NAMEPOOL_DEFAULT_SIZE);
141}
142
143
144void XMLConfiguration::load(std::istream& istr)
145{
146 Poco::XML::InputSource src(istr);
147 load(&src);
148}
149
150
151void XMLConfiguration::load(const std::string& path)
152{
153 Poco::XML::InputSource src(path);
154 load(&src);
155}
156
157
158void XMLConfiguration::load(const Poco::XML::Document* pDocument)
159{
160 poco_check_ptr (pDocument);
161
162 _pDocument = Poco::XML::AutoPtr<Poco::XML::Document>(const_cast<Poco::XML::Document*>(pDocument), true);
163 _pRoot = Poco::XML::AutoPtr<Poco::XML::Node>(pDocument->documentElement(), true);
164}
165
166
167void XMLConfiguration::load(const Poco::XML::Node* pNode)
168{
169 poco_check_ptr (pNode);
170
171 if (pNode->nodeType() == Poco::XML::Node::DOCUMENT_NODE)
172 {
173 load(static_cast<const Poco::XML::Document*>(pNode));
174 }
175 else
176 {
177 _pDocument = Poco::XML::AutoPtr<Poco::XML::Document>(pNode->ownerDocument(), true);
178 _pRoot = Poco::XML::AutoPtr<Poco::XML::Node>(const_cast<Poco::XML::Node*>(pNode), true);
179 }
180}
181
182
183void XMLConfiguration::loadEmpty(const std::string& rootElementName)
184{
185 _pDocument = new Poco::XML::Document;
186 _pRoot = _pDocument->createElement(rootElementName);
187 _pDocument->appendChild(_pRoot);
188}
189
190
191void XMLConfiguration::save(const std::string& path) const
192{
193 Poco::XML::DOMWriter writer;
194 writer.setNewLine("\n");
195 writer.setOptions(Poco::XML::XMLWriter::PRETTY_PRINT);
196 writer.writeNode(path, _pDocument);
197}
198
199
200void XMLConfiguration::save(std::ostream& ostr) const
201{
202 Poco::XML::DOMWriter writer;
203 writer.setNewLine("\n");
204 writer.setOptions(Poco::XML::XMLWriter::PRETTY_PRINT);
205 writer.writeNode(ostr, _pDocument);
206}
207
208
209void XMLConfiguration::save(Poco::XML::DOMWriter& writer, const std::string& path) const
210{
211 writer.writeNode(path, _pDocument);
212}
213
214
215void XMLConfiguration::save(Poco::XML::DOMWriter& writer, std::ostream& ostr) const
216{
217 writer.writeNode(ostr, _pDocument);
218}
219
220
221bool XMLConfiguration::getRaw(const std::string& key, std::string& value) const
222{
223 const Poco::XML::Node* pNode = findNode(key);
224 if (pNode)
225 {
226 value = pNode->innerText();
227 return true;
228 }
229 else return false;
230}
231
232
233void XMLConfiguration::setRaw(const std::string& key, const std::string& value)
234{
235 std::string::const_iterator it = key.begin();
236 Poco::XML::Node* pNode = findNode(it, key.end(), _pRoot, true);
237 if (pNode)
238 {
239 unsigned short nodeType = pNode->nodeType();
240 if (Poco::XML::Node::ATTRIBUTE_NODE == nodeType)
241 {
242 pNode->setNodeValue(value);
243 }
244 else if (Poco::XML::Node::ELEMENT_NODE == nodeType)
245 {
246 Poco::XML::Node* pChildNode = pNode->firstChild();
247 if (pChildNode)
248 {
249 if (Poco::XML::Node::TEXT_NODE == pChildNode->nodeType())
250 {
251 pChildNode->setNodeValue(value);
252 }
253 }
254 else
255 {
256 Poco::AutoPtr<Poco::XML::Node> pText = _pDocument->createTextNode(value);
257 pNode->appendChild(pText);
258 }
259 }
260 }
261 else throw NotFoundException("Node not found in XMLConfiguration", key);
262}
263
264
265void XMLConfiguration::enumerate(const std::string& key, Keys& range) const
266{
267 using Poco::NumberFormatter;
268
269 std::multiset<std::string> keySet;
270 const Poco::XML::Node* pNode = findNode(key);
271 if (pNode)
272 {
273 const Poco::XML::Node* pChild = pNode->firstChild();
274 while (pChild)
275 {
276 if (pChild->nodeType() == Poco::XML::Node::ELEMENT_NODE)
277 {
278 const std::string& nodeName = pChild->nodeName();
279 int n = (int) keySet.count(nodeName);
280 if (n)
281 range.push_back(nodeName + "[" + NumberFormatter::format(n) + "]");
282 else
283 range.push_back(nodeName);
284 keySet.insert(nodeName);
285 }
286 pChild = pChild->nextSibling();
287 }
288 }
289}
290
291
292void XMLConfiguration::removeRaw(const std::string& key)
293{
294 Poco::XML::Node* pNode = findNode(key);
295
296 if (pNode)
297 {
298 if (pNode->nodeType() == Poco::XML::Node::ELEMENT_NODE)
299 {
300 Poco::XML::Node* pParent = pNode->parentNode();
301 if (pParent)
302 {
303 pParent->removeChild(pNode);
304 }
305 }
306 else if (pNode->nodeType() == Poco::XML::Node::ATTRIBUTE_NODE)
307 {
308 Poco::XML::Attr* pAttr = dynamic_cast<Poco::XML::Attr*>(pNode);
309 Poco::XML::Element* pOwner = pAttr->ownerElement();
310 if (pOwner)
311 {
312 pOwner->removeAttributeNode(pAttr);
313 }
314 }
315 }
316}
317
318
319const Poco::XML::Node* XMLConfiguration::findNode(const std::string& key) const
320{
321 std::string::const_iterator it = key.begin();
322 Poco::XML::Node* pRoot = const_cast<Poco::XML::Node*>(_pRoot.get());
323 return findNode(it, key.end(), pRoot);
324}
325
326
327Poco::XML::Node* XMLConfiguration::findNode(const std::string& key)
328{
329 std::string::const_iterator it = key.begin();
330 Poco::XML::Node* pRoot = const_cast<Poco::XML::Node*>(_pRoot.get());
331 return findNode(it, key.end(), pRoot);
332}
333
334
335Poco::XML::Node* XMLConfiguration::findNode(std::string::const_iterator& it, const std::string::const_iterator& end, Poco::XML::Node* pNode, bool create) const
336{
337 if (pNode && it != end)
338 {
339 if (*it == '[')
340 {
341 ++it;
342 if (it != end && *it == '@')
343 {
344 ++it;
345 std::string attr;
346 while (it != end && *it != ']' && *it != '=') attr += *it++;
347 if (it != end && *it == '=')
348 {
349 ++it;
350 std::string value;
351 if (it != end && *it == '\'')
352 {
353 ++it;
354 while (it != end && *it != '\'') value += *it++;
355 if (it != end) ++it;
356 }
357 else
358 {
359 while (it != end && *it != ']') value += *it++;
360 }
361 if (it != end) ++it;
362 return findNode(it, end, findElement(attr, value, pNode), create);
363 }
364 else
365 {
366 if (it != end) ++it;
367 return findAttribute(attr, pNode, create);
368 }
369 }
370 else
371 {
372 std::string index;
373 while (it != end && *it != ']') index += *it++;
374 if (it != end) ++it;
375 return findNode(it, end, findElement(Poco::NumberParser::parse(index), pNode, create), create);
376 }
377 }
378 else
379 {
380 while (it != end && *it == _delim) ++it;
381 std::string key;
382 while (it != end && *it != _delim && *it != '[') key += *it++;
383 return findNode(it, end, findElement(key, pNode, create), create);
384 }
385 }
386 else return pNode;
387}
388
389
390Poco::XML::Node* XMLConfiguration::findElement(const std::string& name, Poco::XML::Node* pNode, bool create)
391{
392 Poco::XML::Node* pChild = pNode->firstChild();
393 while (pChild)
394 {
395 if (pChild->nodeType() == Poco::XML::Node::ELEMENT_NODE && pChild->nodeName() == name)
396 return pChild;
397 pChild = pChild->nextSibling();
398 }
399 if (create)
400 {
401 Poco::AutoPtr<Poco::XML::Element> pElem = pNode->ownerDocument()->createElement(name);
402 pNode->appendChild(pElem);
403 return pElem;
404 }
405 else return 0;
406}
407
408
409Poco::XML::Node* XMLConfiguration::findElement(int index, Poco::XML::Node* pNode, bool create)
410{
411 Poco::XML::Node* pRefNode = pNode;
412 if (index > 0)
413 {
414 pNode = pNode->nextSibling();
415 while (pNode)
416 {
417 if (pNode->nodeName() == pRefNode->nodeName())
418 {
419 if (--index == 0) break;
420 }
421 pNode = pNode->nextSibling();
422 }
423 }
424 if (!pNode && create)
425 {
426 if (index == 1)
427 {
428 Poco::AutoPtr<Poco::XML::Element> pElem = pRefNode->ownerDocument()->createElement(pRefNode->nodeName());
429 pRefNode->parentNode()->appendChild(pElem);
430 return pElem;
431 }
432 else throw Poco::InvalidArgumentException("Element index out of range.");
433 }
434 return pNode;
435}
436
437
438Poco::XML::Node* XMLConfiguration::findElement(const std::string& attr, const std::string& value, Poco::XML::Node* pNode)
439{
440 Poco::XML::Node* pRefNode = pNode;
441 Poco::XML::Element* pElem = dynamic_cast<Poco::XML::Element*>(pNode);
442 if (!(pElem && pElem->getAttribute(attr) == value))
443 {
444 pNode = pNode->nextSibling();
445 while (pNode)
446 {
447 if (pNode->nodeName() == pRefNode->nodeName())
448 {
449 pElem = dynamic_cast<Poco::XML::Element*>(pNode);
450 if (pElem && pElem->getAttribute(attr) == value) break;
451 }
452 pNode = pNode->nextSibling();
453 }
454 }
455 return pNode;
456}
457
458
459Poco::XML::Node* XMLConfiguration::findAttribute(const std::string& name, Poco::XML::Node* pNode, bool create)
460{
461 Poco::XML::Node* pResult(0);
462 Poco::XML::Element* pElem = dynamic_cast<Poco::XML::Element*>(pNode);
463 if (pElem)
464 {
465 pResult = pElem->getAttributeNode(name);
466 if (!pResult && create)
467 {
468 Poco::AutoPtr<Poco::XML::Attr> pAttr = pNode->ownerDocument()->createAttribute(name);
469 pElem->setAttributeNode(pAttr);
470 return pAttr;
471 }
472 }
473 return pResult;
474}
475
476
477} } // namespace Poco::Util
478
479#endif // POCO_UTIL_NO_XMLCONFIGURATION
480