1 /**
2  * Copyright: Copyright (c) 2009 Jacob Carlborg.
3  * Authors: Jacob Carlborg
4  * Version: Initial created: May 18, 2009
5  * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
6  */
7 module mambo.xml.SimpleXML;
8 
9 
10 import tango.io.device.File;
11 import tango.text.xml.Document;
12 import tango.text.xml.DocPrinter;
13 import tango.text.xml.PullParser;
14 import Convert = tango.util.Convert;
15 
16 /**
17  * XML documents. The tradeoff with such a scheme is that copying
18  *
19  *
20  * Implements an easy to use interface on top of a DOM Document.
21  *
22  * Parse example:
23  * ---
24  * auto doc = new SimpleXML!(char)(content);
25  * Stdout(doc).newline;
26  * ---
27  *
28  * API example:
29  * ---
30  * auto doc = new SimpleXML!(char);
31  *
32  * // attach an xml header
33  * doc.header;
34  *
35  * // attach an element with some attributes, plus
36  * // a child element with an attached data value
37  * doc ~ "element"
38  * 	~ doc.Attribute("attrib1", "value")
39  * 	~ doc.Attribute("attrib2")
40  * 	~ doc.Element("child", "value");
41  *
42  * // attach a single child element to the root element
43  * // and a single attribute to the root element
44  * doc ~= "element2";
45  * doc.attribute ~= "attri3";
46  * ---
47  *
48  * X-Path example:
49  * ---
50  * auto doc = new SimpleXML!(char);
51  *
52  * // attach an xml header
53  * doc.header;
54  *
55  * // attach an element with some attributes, plus
56  * // a child element with an attached data value
57  * doc ~ "element"
58  * 	~ doc.Attribute("attrib1", "value")
59  * 	~ doc.Attribute("attrib2")
60  * 	~ doc.Element("child", "value");
61  *
62  * // select named-element
63  * auto set = doc["child"];
64  *
65  * // select the first attribute named "
66  * // attrib2" in the root element
67  * auto att = doc.attribute("attrib2");
68  *
69  * // get the value of the first attribute
70  * // named attrib1 in the root element
71  * char[] value = doc.attribute["attrib1"];
72  * ---
73  */
74 class SimpleXML (T) : Document!(T)
75 {
76 	private DocPrinter!(T) printer;
77 
78 	/**
79 	 * XML documents. The tradeoff with such a scheme is that copying
80 	 *
81 	 * Constructs a SimpleXML instance.
82 	 *
83 	 * Params:
84 	 *     nodes = the initial number of nodes assigned to the freelist
85 	 */
86 	this (uint nodes = 1000)
87 	{
88 		super(nodes);
89 		printer = new DocPrinter!(char);
90 
91 		if (elements)
92 			attribute.node = elements;
93 
94 		else
95 			attribute.node = tree;
96 	}
97 
98 	/**
99 	 * Constructs a SimpleXML instance and parses the given content.
100 	 *
101 	 * Params:
102 	 *     xml = the content to parse
103 	 */
104 	this (T[] xml)
105 	{
106 		this();
107 		parse(xml);
108 	}
109 
110 	/**
111 	 * Prepend an XML header to the document tree.
112 	 *
113 	 * Params:
114 	 *     encoding = the encoding of the XML header
115 	 *
116 	 * Returns: this
117 	 */
118 	final SimpleXML header (T[] encoding = null)
119 	{
120 		super.header = encoding;
121 		return this;
122 	}
123 
124 	/**
125 	 * Returns the first child element of the root element, which
126 	 * matches the given name.
127 	 *
128 	 * Params:
129 	 *     name = the name of the child element
130 	 *
131 	 * Returns: the child element or null
132 	 */
133 	final Node opIndex (T[] name)
134 	{
135 		if (!elements)
136 			return Node.init;
137 
138 		auto set = elements.query[name];
139 
140 		if (set.count > 0)
141 			return Node(set.nodes[0]);
142 
143 		return Node.init;
144 	}
145 
146 	/**
147 	 * Finds the first child element of the root element with the given
148 	 * name and sets it's value to the given value. If the element
149 	 * could not be found it's created and the give value is set.
150 	 *
151 	 * Params:
152 	 *     value = the value to set
153 	 *     name = the name of the element
154 	 */
155 	final void opIndexAssign (T2) (T2 value, T[] name)
156 	{
157 		auto node = this[name];
158 		T[] v;
159 
160 		static if (is(T2 : T[]))
161 			v = value;
162 
163 		else static if (is(T2 == bool))
164 			T[] v = value ? "1" : "0";
165 
166 		else static if (is(T2 : long))
167 			T[] v = Convert.to!(T[])(value);
168 
169 		if (node.node)
170 			node.value = value;
171 
172 		else
173 		{
174 			if (elements)
175 				elements.element(null, name, value);
176 
177 			else
178 				tree.element(null, name, value);
179 		}
180 	}
181 
182 	/**
183 	 * Iterates over the children of the root node
184 	 *
185 	 * Params:
186 	 *     dg = the node and the value of the node will be passed to this for every iteration
187 	 *
188 	 * Returns:
189 	 */
190 	final int opApply (int delegate(ref Node) dg)
191     {
192 		if (!elements)
193 			return 0;
194 
195     	int result;
196 
197     	foreach (n ; elements.children)
198     		if (n.type == XmlNodeType.Element && (result = dg(Node(n))) != 0)
199     			break;
200 
201     	return result;
202     }
203 
204 	/**
205 	 * Adds a new element to the root element of the document.
206 	 *
207 	 * Params:
208 	 *     name = the name of the element
209 	 *     value = the value of the element
210 	 *
211 	 * Returns:a reference to the element
212 	 */
213 	final Node add (T[] name, T[] value = null)
214 	{
215 		if (elements)
216 			return Node(elements.element(null, name, value));
217 
218 		Node node = Node(tree.element(null, name, value));
219 		attribute.node = node.node;
220 
221 		return node;
222 	}
223 
224 	/**
225 	 * Adds a new element to the root element of the document.
226 	 *
227 	 * Params:
228 	 *     name = the name of the element
229 	 *     value = the value of the element
230 	 *
231 	 * Returns:a reference to the element
232 	 */
233 	final Node add (Element element)
234 	{
235 		if (elements)
236 			return Node(elements.element(null, element.name, element.value));
237 
238 		Node node = Node(tree.element(null, element.name, element.value));
239 		attribute.node = node.node;
240 
241 		return node;
242 	}
243 
244 	/**
245 	 * Adds the given attribute to the root element of the document.
246 	 *
247 	 * Params:
248 	 *     element = the element to add
249 	 *
250 	 * Returns: a reference to the element
251 	 */
252 	final Node add (Attribute attribute)
253 	{
254 		if (elements)
255 			return Node(elements.attribute(null, attribute.name, attribute.value));
256 
257 		Node node = Node(tree.attribute(null, attribute.name, attribute.value));
258 		SimpleXML.attribute.node = node.node;
259 
260 		return node;
261 	}
262 
263 	///
264 	alias add opCat;
265 
266 	///
267 	alias add opCatAssign;
268 
269 	/**
270 	 * Returns a string representation of the document. It will return
271 	 * the whole tree as a string.
272 	 *
273 	 * Returns: a string representation of the document
274 	 */
275 	char[] toString ()
276 	{
277 		return printer.print(this);
278 	}
279 
280 	/**
281 	 * This struct represents a node in the tree
282 	 */
283 	static struct Node
284 	{
285 		private Document!(T).Node node;
286 
287 		/**
288 		 * This is an attribute proxy allowing to perform attribute
289 		 * operations on all the attributes in this element.
290 		 */
291 		AttributeProxy attribute;
292 
293 		/**
294 		 * Creates a new Node.
295 		 *
296 		 * Params:
297 		 *     node = the internal node implementation
298 		 *
299 		 * Returns: the newly create node
300 		 */
301 	   	static Node opCall (Document!(T).Node node)
302 	    {
303 	    	Node n;
304 	    	n.node = node;
305 	    	n.attribute.node = node;
306 
307 	    	return n;
308 	    }
309 
310 	   	/**
311 	   	 * Gets the name of the node.
312 	   	 *
313 	   	 * Returns: the name of the node
314 	   	 */
315 	   	T[] name ()
316 	   	{
317 	   		return node.name;
318 	   	}
319 
320 	   	/**
321 	   	 * Sets the name of the node.
322 	   	 *
323 	   	 * Params:
324 	   	 *     name = the name to set
325 	   	 *
326 	   	 * Returns: the name of the node
327 	   	 */
328 	   	T[] name (T[] name)
329 	   	{
330 	   		node.name = name;
331 	   		return node.name;
332 	   	}
333 
334 	   	/**
335 	   	 * Gets the value of the node.
336 	   	 *
337 	   	 * Returns: the value of the node
338 	   	 */
339 	   	T[] value ()
340 	   	{
341 	   		return node.value;
342 	   	}
343 
344 	   	/**
345 	   	 * Sets the value of the node.
346 	   	 *
347 	   	 * Params:
348 	   	 *     value = the value to set
349 	   	 *
350 	   	 * Returns: the value of the noe
351 	   	 */
352 	   	T[] value (T[] value)
353 	   	{
354 	   		node.value = value;
355 	   		return node.value;
356 	   	}
357 
358 		/**
359 		 * Returns the first child element of the node, which matches the
360 		 * given name.
361 		 *
362 		 * Params:
363 		 *     name = the name of the element
364 		 *
365 		 * Returns: the child element or this
366 		 */
367 		Node opIndex (T[] name)
368 		{
369 			auto set = node.query[name];
370 
371 			if (set.count > 0)
372 				return Node(set.nodes[0]);
373 
374 			return *this;
375 		}
376 
377 		/**
378 		 * Iterates over the children of the node
379 		 *
380 		 * Params:
381 		 *     dg = the node and the value of the node will be passed to this for every iteration
382 		 *
383 		 * Returns:
384 		 */
385 		int opApply (int delegate(ref Node) dg)
386 	    {
387 			if (!node)
388 				return 0;
389 
390 	    	int result;
391 
392 	    	foreach (n ; node.children)
393 	    		if (n.type == XmlNodeType.Element && (result = dg(Node(n))) != 0)
394 	    			break;
395 
396 	    	return result;
397 	    }
398 
399 		/**
400 		 * Adds a new element to this element.
401 		 *
402 		 * Params:
403 		 *     name = the name of the element
404 		 *     value = the value of the element
405 		 *
406 		 * Returns:
407 		 */
408 		Node add (T[] name, T[] value = null)
409 		{
410 			return Node(node.element(null, name, value));
411 		}
412 
413 		/**
414 		 * Adds a new element to this element.
415 		 *
416 		 * Params:
417 		 *     name = the name of the element
418 		 *
419 		 * Returns: a reference to the element
420 		 */
421 	   	Node add (SimpleXML.Element element)
422 	    {
423 	    	return Node(node.element(null, element.name, element.value));
424 	    }
425 
426 		/**
427 		 * Adds a new attribute to this element.
428 		 *
429 		 * Params:
430 		 *     attribute = the attribute
431 		 *
432 		 * Returns: a reference to the element
433 		 */
434 	   	Node add (Attribute attribute)
435 	    {
436 	    	return Node(node.attribute(null, attribute.name, attribute.value));
437 	    }
438 
439 	   	///
440 	   	alias add opCat;
441 
442 	   	///
443 	   	alias add opCatAssign;
444 
445 		/**
446 		 * Finds the first child element of this element with the given
447 		 * name and sets it's value to the given value. If the element
448 		 * could not be found it's created and the give value is set.
449 		 *
450 		 * Params:
451 		 *     value = the value to set
452 		 *     name = the name of the element
453 		 */
454    		void opIndexAssign (T2) (T2 value, T[] name)
455    		{
456    			static if (is(T2 : T[]))
457    			{
458    				if (auto node = node.attributes.name(null, name))
459    					node.value = value;
460 
461    				else
462    					node.attribute(null, name, value);
463    			}
464 
465    			else static if (is(T2 == bool))
466    			{
467    				T[] v = value ? "1" : "0";
468 
469    				if (auto n = node.attributes.name(null, name))
470    					n.value = v;
471 
472    				else
473    					node.attribute(null, name, v);
474    			}
475 
476    			else static if (is(T2 : long))
477    			{
478    				T[] v = Convert.to!(T[])(value);
479 
480    				if (auto n = node.attributes.name(null, name))
481    					n.value = v;
482 
483    				else
484    					node.attribute(null, name, v);
485    			}
486    		}
487 
488    		/**
489    		 * Returns a string representation of this object which is the
490    		 * value of the node
491    		 *
492    		 * Returns: a string representation (the value)
493    		 */
494 	   	T[] toString ()
495 	   	{
496 	   		return value;
497 	   	}
498 
499 	   	/**
500 	   	 * This struct represents an attribute proxy. This is the type
501 	   	 * that is returned when calling Node.attribute and lets you
502 	   	 * perform operations on attributes.
503 	   	 */
504 	   	static struct AttributeProxy
505 	   	{
506 	   		private Document!(T).Node node;
507 
508 			/**
509 			 * Finds the attribute with the given name in the element of
510 			 * which this attribute proxy was returned.
511 			 *
512 			 * Params:
513 			 *     name = the name of the attribute
514 			 *
515 			 * Returns: an attribute proxy
516 			 */
517 	   		AttributeProxy opCall (T[] name)
518 	   		{
519 	   			AttributeProxy a;
520 	   			a.node = node.attributes.name(null, name);
521 
522 	   			return a;
523 	   		}
524 
525 	   		/**
526 	   		 * Gets the name of the attribute
527 	   		 *
528 	   		 * Returns: the name of the attribute
529 	   		 */
530 		   	T[] name ()
531 		   	{
532 		   		return node.name;
533 		   	}
534 
535 		   	/**
536 		   	 * Sets the name of the attribute
537 		   	 *
538 		   	 * Params:
539 		   	 *     name = the name of the attribute
540 		   	 *
541 		   	 * Returns: the name of the attribute
542 		   	 */
543 		   	T[] name (T[] name)
544 		   	{
545 		   		node.name = name;
546 		   		return node.name;
547 		   	}
548 
549 		   	/**
550 	   		 * Gets the value of the attribute
551 	   		 *
552 	   		 * Returns: the value of the attribute
553 	   		 */
554 		   	T[] value ()
555 		   	{
556 		   		return node.value;
557 		   	}
558 
559 		   	/**
560 		   	 * Sets the value of the attribute
561 		   	 *
562 		   	 * Params:
563 		   	 *     value = the value of the attribute
564 		   	 *
565 		   	 * Returns: the value of the attribute
566 		   	 */
567 		   	T[] value (T[] value)
568 		   	{
569 		   		node.value = value;
570 		   		return node.value;
571 		   	}
572 
573 		   	/**
574 		   	 * Returns the value of the attribute with the given name
575 		   	 *
576 		   	 * Params:
577 		   	 *     name = the name of the attribute
578 		   	 *
579 		   	 * Returns: the value of the attribute of null
580 		   	 */
581 	   		T[] opIndex (T[] name)
582 	   		{
583 	   			if (auto node = node.attributes.name(null, name))
584 	   				return node.value;
585 
586 	   			return null;
587 	   		}
588 
589 			/**
590 			 * Finds the attribute with the given name in the element of which
591 			 * this proxy object was received name and sets it's value to the
592 			 * given value. If the element could not be found it's created and
593 			 * the give value is set.
594 			 *
595 			 * Params:
596 			 *     value = the value to set
597 			 *     name = the name of the element
598 			 */
599 	   		void opIndexAssign (T2) (T2 value, T[] name)
600 	   		{
601 	   			static if (is(T2 : T[]))
602 	   			{
603 	   				if (auto node = node.attributes.name(null, name))
604 	   					node.value = value;
605 	   				else
606 	   					node.attribute(null, name, value);
607 	   			}
608 
609 	   			else static if (is(T2 == bool))
610 	   			{
611 	   				T[] v = value ? "1" : "0";
612 
613 	   				if (auto n = node.attributes.name(null, name))
614 	   					n.value = v;
615 
616 	   				else
617 	   					node.attribute(null, name, v);
618 	   			}
619 
620 	   			else static if (is(T2 : long))
621 	   			{
622 	   				T[] v = Convert.to!(T[])(value);
623 
624 	   				if (auto n = node.attributes.name(null, name))
625 	   					n.value = v;
626 
627 	   				else
628 	   					node.attribute(null, name, v);
629 	   			}
630 	   		}
631 
632 	   		/**
633 	   		 * Returns the value of the first attribute in the element of which
634 	   		 * this proxy object was received, which matches the given name.
635 	   		 *
636 	   		 * Params:
637 	   		 *     name = the name of the attribute
638 	   		 *     aDefault = the default return value
639 	   		 *
640 	   		 * Returns: true if the attribute was found and it's value was 1, otherwise aDefault
641 	   		 */
642 	   		bool getBool (T[] name, bool aDefault = false)
643 	   		{
644 	   			return (*this)[name] == "1" ? true : aDefault;
645 	   		}
646 
647 	   		/**
648 	   		 * Returns the value of the first attribute in the element of which
649 	   		 * this proxy object was received, which matches the given name.
650 	   		 *
651 	   		 * Params:
652 	   		 *     name = the name of the attribute
653 	   		 *     aDefault = the default return value
654 	   		 *
655 	   		 * Returns: the value of the attribute if it was found and could be
656 	   		 * 			converted to a long, otherwise aDefault.
657 	   		 */
658 	   		long getLong (T[] name, long aDefault = 0)
659 	   		{
660 	   			return Convert.to!(long)((*this)[name], aDefault);
661 	   		}
662 
663 	   		/**
664 	   		 * Returns the value of the first attribute in the element of which
665 	   		 * this proxy object was received, which matches the given name.
666 	   		 *
667 	   		 * Params:
668 	   		 *     name = the name of the attribute
669 	   		 *     aDefault = the default return value
670 	   		 *
671 	   		 * Returns: the value of the attribute if it was found and could be
672 	   		 * 			converted to an int, otherwise aDefault.
673 	   		 */
674 	   		int getInt (T[] name, int aDefault = 0)
675 	   		{
676 	   			return Convert.to!(int)((*this)[name], aDefault);
677 	   		}
678 
679 	   		/**
680 	   		 * Adds a new attribute to the element the element of which this
681 	   		 * proxy object was received.
682 	   		 *
683 	   		 * Params:
684 	   		 *     name = the name of the attribute
685 	   		 *     value = the value of the attribute
686 	   		 *
687 	   		 * Returns: the element this attribute was added
688 	   		 */
689 	   		Node add (T[] name, T[] value = null)
690 	   		{
691 	   			return Node(node.attribute(null, name, value));
692 	   		}
693 
694 			/**
695 			 * Adds a new attribute to the element the element of which this
696 	   		 * proxy object was received.
697 			 *
698 			 * Params:
699 			 *     name = the name of the element
700 			 *
701 			 * Returns: the element this attribute was added
702 			 */
703 	   		Node add (Attribute attribute)
704 	   		{
705 	   			return Node(node.attribute(null, attribute.name, attribute.value));
706 	   		}
707 
708 
709 	   		/**
710 	   		 * Adds a new attribute to the element the element of which this
711 	   		 * proxy object was received.
712 	   		 *
713 	   		 * Params:
714 	   		 *     name = the name of the attribute
715 	   		 *     value = the value of the attribute
716 	   		 *
717 	   		 * Returns: the element this attribute was added
718 	   		 */
719 	   		Node add (T[] name, bool value)
720 	   		{
721 	   			return Node(node.attribute(null, name, value ? "1" : "0"));
722 	   		}
723 
724 	   		/**
725 	   		 * Adds a new attribute to the element the element of which this
726 	   		 * proxy object was received.
727 	   		 *
728 	   		 * Params:
729 	   		 *     name = the name of the attribute
730 	   		 *     value = the value of the attribute
731 	   		 *
732 	   		 * Returns: the element this attribute was added
733 	   		 */
734 	   		Node add (T[] name, int value)
735 	   		{
736 	   			return Node(node.attribute(null, name, Convert.toString(value)));
737 	   		}
738 
739 	   		///
740 	   		//alias add opCat;
741 
742 	   		///
743 	   		//alias add opCatAssign;
744 
745 	   		Node opCatAssign (T[] name)
746 	   		{
747 	   			return Node(node.attribute(null, name, null));
748 	   		}
749 
750 	   		/**
751 	   		 * Iterates over the children of the root node
752 	   		 *
753 	   		 * Params:
754 	   		 *     dg = the attribute proxy be passed to this for every iteration
755 	   		 *
756 	   		 * Returns:
757 	   		 */
758 			int opApply (int delegate(ref AttributeProxy) dg)
759 		    {
760 				if (!node)
761 					return 0;
762 
763 		    	int result;
764 
765 		    	foreach (n ; node.attributes)
766 		    	{
767 		    		AttributeProxy a;
768 		    		a.node = n;
769 
770 		    		if (n.type == XmlNodeType.Attribute && (result = dg(a)) != 0)
771 		    			break;
772 		    	}
773 
774 		    	return result;
775 		    }
776 
777 	   		/**
778 	   		 * Returns a string representation of this object which is the
779 	   		 * value of the attribute.
780 	   		 *
781 	   		 * Returns: a string representation (the value)
782 	   		 */
783 		   	T[] toString ()
784 		   	{
785 		   		return value;
786 		   	}
787 	   	}
788 	}
789 
790 	/**
791 	 * This is an attribute proxy allowing to perform attribute
792 	 * operations on all the attributes in the root element of this
793 	 * document.
794 	 */
795 	Node.AttributeProxy attribute;
796 
797 	/// This is a name-value pair representing an attribute
798 	struct Attribute
799 	{
800 		/// The name of this attribute
801 		T[] name;
802 
803 		/// The value of this attribute
804 		T[] value;
805 	}
806 
807 	/// This is a name-value pair representing an element
808 	struct Element
809 	{
810 		/// The name of this element
811 		T[] name;
812 
813 		/// The value of this element
814 		T[] value;
815 	}
816 }