use ObjectURI more consistently
[gnash.git] / libcore / asobj / XMLNode_as.cpp
blobed2997520c24ce2008595ed66232142a792ac69e
1 // XMLNode_as.cpp: ActionScript "XMLNode" class, for Gnash.
2 //
3 // Copyright (C) 2009, 2010 Free Software Foundation, Inc.
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "XMLNode_as.h"
22 #include "XML_as.h"
23 #include "VM.h"
24 #include "log.h"
25 #include "fn_call.h"
26 #include "Global_as.h"
27 #include "smart_ptr.h" // for boost intrusive_ptr
28 #include "builtin_function.h" // need builtin_function
29 #include "NativeFunction.h"
30 #include "VM.h"
31 #include "PropertyList.h"
32 #include "Global_as.h"
33 #include "Object.h"
34 #include "Array_as.h"
36 #include "namedStrings.h"
37 #include <boost/bind.hpp>
38 #include <string>
39 #include <sstream>
40 #include <vector>
41 #include <algorithm>
43 namespace gnash {
45 // Function Prototypes
46 namespace {
47 typedef std::pair<std::string, std::string> StringPair;
48 typedef std::vector<StringPair> StringPairs;
49 void enumerateAttributes(const XMLNode_as& node,
50 StringPairs& attributes);
51 bool prefixMatches(const StringPairs::value_type& val,
52 const std::string& prefix);
53 bool namespaceMatches(
54 const StringPairs::value_type& val,
55 const std::string& ns);
57 as_value xmlnode_new(const fn_call& fn);
58 as_value xmlnode_nodeName(const fn_call& fn);
59 as_value xmlnode_nodeValue(const fn_call& fn);
60 as_value xmlnode_nodeType(const fn_call& fn);
61 as_value xmlnode_attributes(const fn_call& fn);
62 as_value xmlnode_appendChild(const fn_call& fn);
63 as_value xmlnode_cloneNode(const fn_call& fn);
64 as_value xmlnode_lastChild(const fn_call& fn);
65 as_value xmlnode_firstChild(const fn_call& fn);
66 as_value xmlnode_nextSibling(const fn_call& fn);
67 as_value xmlnode_childNodes(const fn_call& fn);
68 as_value xmlnode_previousSibling(const fn_call& fn);
69 as_value xmlnode_parentNode(const fn_call& fn);
70 as_value xmlnode_getNamespaceForPrefix(const fn_call& fn);
71 as_value xmlnode_getPrefixForNamespace(const fn_call& fn);
72 as_value xmlnode_namespaceURI(const fn_call& fn);
73 as_value xmlnode_hasChildNodes(const fn_call& fn);
74 as_value xmlnode_insertBefore(const fn_call& fn);
75 as_value xmlnode_removeNode(const fn_call& fn);
76 as_value xmlnode_toString(const fn_call& fn);
77 as_value xmlnode_localName(const fn_call& fn);
78 as_value xmlnode_prefix(const fn_call& fn);
79 void attachXMLNodeInterface(as_object& o);
82 XMLNode_as::XMLNode_as(Global_as& gl)
84 _global(gl),
85 _object(0),
86 _parent(0),
87 _attributes(new as_object(gl)),
88 _childNodes(0),
89 _type(Element)
93 XMLNode_as::XMLNode_as(const XMLNode_as& tpl, bool deep)
95 _global(tpl._global),
96 _object(0),
97 _parent(0),
98 _attributes(new as_object(_global)),
99 _childNodes(0),
100 _name(tpl._name),
101 _value(tpl._value),
102 _type(tpl._type)
104 // only clone children if in deep mode
105 if (deep) {
106 const Children& from=tpl._children;
107 for (Children::const_iterator it=from.begin(), itEnd=from.end();
108 it != itEnd; ++it) {
109 _children.push_back(new XMLNode_as(*(*it), deep));
114 XMLNode_as::~XMLNode_as()
116 clearChildren();
119 as_object*
120 XMLNode_as::object()
123 // This is almost the same as if the XMLNode constructor were called,
124 // but not quite. There is no __constructor__ property, and when we
125 // override _global.XMLNode, we can show that it is not called.
126 if (!_object) {
127 as_object* o = createObject(_global);
128 as_object* xn =
129 toObject(getMember(_global, NSV::CLASS_XMLNODE), getVM(_global));
130 if (xn) {
131 o->set_prototype(getMember(*xn, NSV::PROP_PROTOTYPE));
132 o->init_member(NSV::PROP_CONSTRUCTOR, xn);
134 o->setRelay(this);
135 setObject(o);
137 return _object;
140 void
141 XMLNode_as::updateChildNodes()
143 if (!_childNodes) return;
145 // Clear array of all elements.
146 _childNodes->set_member(NSV::PROP_LENGTH, 0.0);
148 if (_children.empty()) return;
150 VM& vm = getVM(_global);
152 // Set up the array without calling push()!
153 const size_t size = _children.size();
154 Children::const_iterator it = _children.begin();
155 for (size_t i = 0; i != size; ++i, ++it) {
156 XMLNode_as* node = *it;
157 const ObjectURI& key = arrayKey(vm, i);
158 _childNodes->set_member(key, node->object());
160 // All elements are set to readonly.
161 _childNodes->set_member_flags(key, PropFlags::readOnly);
165 as_object*
166 XMLNode_as::childNodes()
168 if (!_childNodes) {
169 _childNodes = _global.createArray();
170 updateChildNodes();
172 return _childNodes;
175 bool
176 XMLNode_as::hasChildNodes()
178 return !_children.empty();
181 XMLNode_as*
182 XMLNode_as::firstChild()
184 if (_children.empty()) return 0;
185 return _children.front();
188 XMLNode_as*
189 XMLNode_as::cloneNode(bool deep)
191 XMLNode_as* newnode = new XMLNode_as(*this, deep);
192 return newnode;
195 XMLNode_as*
196 XMLNode_as::lastChild()
198 if (_children.empty()) {
199 log_debug(_("XMLNode_as %p has no children"), (void*)this);
200 return 0;
202 return _children.back();
205 void
206 XMLNode_as::removeChild(XMLNode_as* node)
208 node->setParent(0);
209 _children.remove(node);
210 updateChildNodes();
213 void
214 XMLNode_as::appendChild(XMLNode_as* node)
216 assert(node);
217 node->setParent(this);
218 _children.push_back(node);
219 updateChildNodes();
222 void
223 XMLNode_as::insertBefore(XMLNode_as* newnode, XMLNode_as* pos)
225 assert(_object);
227 // find iterator for positional parameter
228 Children::iterator it = std::find(_children.begin(), _children.end(), pos);
229 if (it == _children.end()) {
230 IF_VERBOSE_ASCODING_ERRORS(
231 log_aserror(_("XMLNode.insertBefore(): positional parameter "
232 "is not a child of this node"));
234 return;
237 _children.insert(it, newnode);
239 XMLNode_as* parent = newnode->getParent();
240 if (parent) {
241 parent->removeChild(newnode);
244 newnode->setParent(this);
245 updateChildNodes();
248 XMLNode_as *
249 XMLNode_as::previousSibling()
251 if (!_parent) return 0;
252 if (_parent->_children.size() <= 1) return 0;
254 XMLNode_as *previous_node = 0;
255 for (Children::iterator itx = _parent->_children.begin();
256 itx != _parent->_children.end(); itx++) {
258 if (*itx == this) return previous_node;
260 previous_node = *itx;
263 return 0;
266 XMLNode_as *
267 XMLNode_as::nextSibling()
270 if (!_parent) return 0;
272 if (_parent->_children.size() <= 1) return 0;
274 XMLNode_as *previous_node = 0;
275 for (Children::reverse_iterator itx = _parent->_children.rbegin();
276 itx != _parent->_children.rend(); ++itx) {
278 if (*itx == this) return previous_node;
279 previous_node = *itx;
282 return 0;
285 void
286 XMLNode_as::toString(std::ostream& xmlout, bool encode) const
288 stringify(*this, xmlout, encode);
291 void
292 XMLNode_as::setAttribute(const std::string& name, const std::string& value)
294 if (_attributes) {
295 VM& vm = getVM(_global);
296 _attributes->set_member(getURI(vm, name), value);
300 bool
301 XMLNode_as::getPrefixForNamespace(const std::string& ns, std::string& prefix)
303 XMLNode_as* node = this;
304 StringPairs::const_iterator it;
305 StringPairs attrs;
307 while (node) {
308 enumerateAttributes(*node, attrs);
309 if (!attrs.empty())
311 it = std::find_if(attrs.begin(), attrs.end(),
312 boost::bind(namespaceMatches, _1, ns));
313 if (it != attrs.end()) break;
315 node = node->getParent();
318 // None found.
319 if (!node) return false;
321 // Return the matching prefix
322 const std::string& name = it->first;
324 if (name.length() == 5) {
325 return true;
328 assert (name.length() >= 6);
330 if (name[5] != ':') return false;
332 // Can also be empty.
333 prefix = name.substr(6);
334 return true;
337 void
338 XMLNode_as::getNamespaceForPrefix(const std::string& prefix, std::string& ns)
340 XMLNode_as* node = this;
341 StringPairs::const_iterator it;
342 StringPairs attrs;
344 while (node) {
346 enumerateAttributes(*node, attrs);
348 if (!attrs.empty()) {
350 it = std::find_if(attrs.begin(), attrs.end(),
351 boost::bind(prefixMatches, _1, prefix));
352 if (it != attrs.end()) break;
354 node = node->getParent();
357 // None found; return undefined
358 if (!node) return;
360 // Return the matching namespace
361 ns = it->second;
365 bool
366 XMLNode_as::extractPrefix(std::string& prefix)
368 prefix.clear();
369 if (_name.empty()) return false;
371 std::string::size_type pos = _name.find(':');
372 if (pos == std::string::npos || pos == _name.size() - 1) {
373 return false;
376 prefix = _name.substr(0, pos);
377 return true;
380 void
381 XMLNode_as::clearChildren()
383 for (Children::const_iterator it = _children.begin(), e = _children.end();
384 it != e; ++it) {
385 const XMLNode_as* node = *it;
386 if (!node->_object) {
387 delete node;
390 _children.clear();
392 // Reset so that it is reinitialized on next access.
393 _childNodes = 0;
396 void
397 XMLNode_as::stringify(const XMLNode_as& xml, std::ostream& xmlout, bool encode)
400 const std::string& nodeValue = xml.nodeValue();
401 const std::string& nodeName = xml.nodeName();
402 NodeType type = xml.nodeType();
404 #ifdef GNASH_DEBUG
405 log_debug(_("Stringifying node %p with name %s, as_value %s, %u "
406 "attributes and %u children"), (void*)&xml, nodeName,
407 nodeValue, xml._attributes.size(), xml._children.size());
408 #endif
410 // Create the beginning of the tag
411 if (!nodeName.empty()) {
413 xmlout << "<" << nodeName;
415 // Process the attributes, if any
416 StringPairs attrs;
417 enumerateAttributes(xml, attrs);
418 if (!attrs.empty()) {
420 for (StringPairs::iterator i =
421 attrs.begin(), e = attrs.end(); i != e; ++i) {
422 escapeXML(i->second);
423 xmlout << " " << i->first << "=\"" << i->second << "\"";
427 // If the node has no content, just close the tag now
428 if (nodeValue.empty() && xml._children.empty()) {
429 xmlout << " />";
430 return;
432 else {
433 // Will use a closing tag later
434 xmlout << ">";
439 // Node as_value first, then children
440 if (type == Text)
442 Global_as& gl = xml._global;
444 // Insert entities.
445 std::string escaped(nodeValue);
446 escapeXML(escaped);
447 const std::string& val = encode ?
448 callMethod(&gl, NSV::PROP_ESCAPE, escaped).to_string() :
449 escaped;
451 xmlout << val;
454 // Childs, after node as_value.
455 for (Children::const_iterator itx = xml._children.begin();
456 itx != xml._children.end(); ++itx) {
458 (*itx)->toString(xmlout, encode);
461 if (!nodeName.empty()) {
462 xmlout << "</" << nodeName << ">";
466 void
467 XMLNode_as::setReachable()
469 // If there is a parent, make sure its object is reachable. This goes
470 // up towards the root node of tree without marking the XMLNode
471 // resources (which would cause infinite recursion).
472 if (_parent && _parent->_object) _parent->_object->setReachable();
474 // Mark children
475 std::for_each(_children.begin(), _children.end(),
476 boost::mem_fn(&XMLNode_as::setReachable));
478 // Mark attributes object
479 if (_attributes) _attributes->setReachable();
481 if (_object) _object->setReachable();
483 if (_childNodes) _childNodes->setReachable();
487 void
488 registerXMLNodeNative(as_object& where)
490 VM& vm = getVM(where);
491 vm.registerNative(xmlnode_cloneNode, 253, 1);
492 vm.registerNative(xmlnode_removeNode, 253, 2);
493 vm.registerNative(xmlnode_insertBefore, 253, 3);
494 vm.registerNative(xmlnode_appendChild, 253, 4);
495 vm.registerNative(xmlnode_hasChildNodes, 253, 5);
496 vm.registerNative(xmlnode_toString, 253, 6);
497 vm.registerNative(xmlnode_getNamespaceForPrefix, 253, 7);
498 vm.registerNative(xmlnode_getPrefixForNamespace, 253, 8);
501 void
502 xmlnode_class_init(as_object& where, const ObjectURI& uri)
504 Global_as& gl = getGlobal(where);
505 as_object* proto = createObject(gl);
506 attachXMLNodeInterface(*proto);
507 as_object* cl = gl.createClass(&xmlnode_new, proto);
509 where.init_member(uri, cl, as_object::DefaultFlags);
513 namespace {
515 void
516 attachXMLNodeInterface(as_object& o)
519 VM& vm = getVM(o);
521 const int noFlags = 0;
523 // No prop flags:
524 o.init_member("cloneNode", vm.getNative(253, 1), noFlags);
525 o.init_member("removeNode", vm.getNative(253, 2), noFlags);
526 o.init_member("insertBefore", vm.getNative(253, 3), noFlags);
527 o.init_member("appendChild", vm.getNative(253, 4), noFlags);
528 o.init_member("hasChildNodes", vm.getNative(253, 5), noFlags);
529 o.init_member("toString", vm.getNative(253, 6), noFlags);
530 o.init_member("getNamespaceForPrefix", vm.getNative(253, 7), noFlags);
531 o.init_member("getPrefixForNamespace", vm.getNative(253, 8), noFlags);
533 const int protectedFlags = 0;
535 // Just the protected flag:
537 o.init_readonly_property("attributes", &xmlnode_attributes, protectedFlags);
538 o.init_readonly_property("childNodes", &xmlnode_childNodes, protectedFlags);
539 o.init_readonly_property("firstChild", &xmlnode_firstChild, protectedFlags);
540 o.init_readonly_property("lastChild", &xmlnode_lastChild, protectedFlags);
541 o.init_readonly_property("nextSibling",
542 &xmlnode_nextSibling, protectedFlags);
543 o.init_property("nodeName", &xmlnode_nodeName,
544 &xmlnode_nodeName, protectedFlags);
545 o.init_readonly_property("nodeType", &xmlnode_nodeType, protectedFlags);
546 o.init_property("nodeValue", &xmlnode_nodeValue,
547 &xmlnode_nodeValue, protectedFlags);
548 o.init_readonly_property("parentNode", &xmlnode_parentNode, protectedFlags);
549 o.init_readonly_property("previousSibling",
550 &xmlnode_previousSibling, protectedFlags);
551 o.init_readonly_property("prefix", &xmlnode_prefix, protectedFlags);
552 o.init_readonly_property("localName", &xmlnode_localName, protectedFlags);
553 o.init_readonly_property("namespaceURI",
554 &xmlnode_namespaceURI, protectedFlags);
558 as_value
559 xmlnode_new(const fn_call& fn)
562 as_object* obj = ensure<ValidThis>(fn);
564 if (!fn.nargs) {
565 return as_value();
568 std::auto_ptr<XMLNode_as> xml(new XMLNode_as(getGlobal(fn)));
569 xml->nodeTypeSet(XMLNode_as::NodeType(toInt(fn.arg(0), getVM(fn))));
571 if (fn.nargs > 1) {
572 const std::string& str = fn.arg(1).to_string();
573 switch (xml->nodeType())
575 case XMLNode_as::Element:
576 xml->nodeNameSet(str);
577 break;
578 default:
579 xml->nodeValueSet(str);
580 break;
584 // This sets the relay!
585 xml->setObject(obj);
586 obj->setRelay(xml.release());
588 return as_value();
592 as_value
593 xmlnode_appendChild(const fn_call& fn)
596 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
598 if (!fn.nargs) {
599 IF_VERBOSE_ASCODING_ERRORS(
600 log_aserror(_("XMLNode::appendChild() needs at least one "
601 "argument"));
603 return as_value();
606 XMLNode_as* node;
607 if (!isNativeType(toObject(fn.arg(0), getVM(fn)), node)) {
608 IF_VERBOSE_ASCODING_ERRORS(
609 log_aserror(_("First argument to XMLNode::appendChild() is not "
610 "an XMLNode"));
612 return as_value();
615 XMLNode_as* parent = node->getParent();
616 if (parent) {
617 parent->removeChild(node);
619 ptr->appendChild(node);
621 return as_value();
625 as_value
626 xmlnode_cloneNode(const fn_call& fn)
628 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
630 bool deep = false;
631 if (fn.nargs > 0) deep = toBool(fn.arg(0), getVM(fn));
633 as_object* newnode = ptr->cloneNode(deep)->object();
634 return as_value(newnode);
638 as_value
639 xmlnode_insertBefore(const fn_call& fn)
641 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
643 if ( fn.nargs < 2 )
645 IF_VERBOSE_ASCODING_ERRORS(
646 std::stringstream ss; fn.dump_args(ss);
647 log_aserror(_("XMLNode.insertBefore(%s) needs at least two "
648 "arguments"), ss.str());
650 return as_value();
653 XMLNode_as* newnode;
655 if (!isNativeType(toObject(fn.arg(0), getVM(fn)), newnode)) {
656 IF_VERBOSE_ASCODING_ERRORS(
657 std::stringstream ss; fn.dump_args(ss);
658 log_aserror(_("First argument to XMLNode.insertBefore(%s) is not "
659 "an XMLNode"), ss.str());
661 return as_value();
664 XMLNode_as* pos;
666 if (!isNativeType(toObject(fn.arg(1), getVM(fn)), pos)) {
667 IF_VERBOSE_ASCODING_ERRORS(
668 std::stringstream ss; fn.dump_args(ss);
669 log_aserror(_("Second argument to XMLNode.insertBefore(%s) is not "
670 "an XMLNode"), ss.str());
672 return as_value();
675 ptr->insertBefore(newnode, pos);
676 return as_value();
681 as_value
682 xmlnode_getNamespaceForPrefix(const fn_call& fn)
684 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
685 if (!fn.nargs) {
686 return as_value();
689 std::string ns;
691 ptr->getNamespaceForPrefix(fn.arg(0).to_string(), ns);
692 if (ns.empty()) return as_value();
693 return as_value(ns);
697 as_value
698 xmlnode_getPrefixForNamespace(const fn_call& fn)
700 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
701 if (!fn.nargs) {
702 return as_value();
705 std::string prefix;
707 // Return undefined if none found; otherwise the prefix string found.
708 // This can be empty if it is a standard namespace.
709 if (!ptr->getPrefixForNamespace(fn.arg(0).to_string(), prefix)) {
710 return as_value();
712 return as_value(prefix);
715 /// If the node has a prefix, return the matching namespace. Otherwise,
716 /// returns a namespaceURI set with the xmlns attribute, searching upwards
717 /// through parent nodes if necessary.
719 /// This standard namespace can only be set during XML parsing and cannot
720 /// be changed or set using attributes.
722 /// Conversely, the similar getNamespaceForPrefix("") can be set and changed
723 /// through attributes.
724 as_value
725 xmlnode_namespaceURI(const fn_call& fn)
727 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
729 // Read-only property
731 const std::string& name = ptr->nodeName();
733 if (name.empty()) {
734 as_value null;
735 null.set_null();
736 return null;
739 std::string prefix;
740 if (ptr->extractPrefix(prefix)) {
741 std::string ns;
742 ptr->getNamespaceForPrefix(prefix, ns);
743 return as_value(ns);
746 // Search recursively for a namespace. Return an empty string
747 // if none found.
748 XMLNode_as* node = ptr;
749 while (node && node->getNamespaceURI().empty()) {
750 node = node->getParent();
752 if (!node) return as_value("");
754 return as_value(node->getNamespaceURI());
758 // Return the prefix part of the node name. If there is no colon, or one
759 // colon at the end of the string, this is empty. Otherwise it is the part
760 // up to the first colon.
761 as_value
762 xmlnode_prefix(const fn_call& fn)
764 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
766 // Read-only property
768 if (ptr->nodeName().empty()) {
769 as_value null;
770 null.set_null();
771 return null;
774 std::string prefix;
775 if (!ptr->extractPrefix(prefix)) return as_value("");
776 return as_value(prefix);
780 // The local part of a node name. If there is no colon or a single colon
781 // at the end of the string, this is the whole string. Otherwise all of the
782 // string after the first colon.
783 as_value
784 xmlnode_localName(const fn_call& fn)
786 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
788 // Read-only property
790 if (ptr->nodeName().empty()) {
791 as_value null;
792 null.set_null();
793 return null;
796 const std::string& nodeName = ptr->nodeName();
797 if (nodeName.empty()) return as_value("");
799 std::string::size_type pos = nodeName.find(':');
800 if (pos == std::string::npos || pos == nodeName.size() - 1) {
801 return as_value(nodeName);
804 return as_value(nodeName.substr(pos + 1));
808 as_value
809 xmlnode_removeNode(const fn_call& fn)
811 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
813 XMLNode_as* parent = ptr->getParent();
814 if (parent) parent->removeChild(ptr);
815 return as_value();
819 as_value
820 xmlnode_toString(const fn_call& fn)
823 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
825 std::stringstream ss;
826 ptr->toString(ss);
828 return as_value(ss.str());
832 as_value
833 xmlnode_hasChildNodes(const fn_call& fn)
835 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
836 return as_value(ptr->hasChildNodes());
840 as_value
841 xmlnode_nodeValue(const fn_call& fn)
843 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
844 as_value rv;
845 rv.set_null();
847 if ( fn.nargs == 0 )
849 const std::string& val = ptr->nodeValue();
850 if ( ! val.empty() ) rv = val;
852 else
854 ptr->nodeValueSet(fn.arg(0).to_string());
856 return rv;
860 as_value
861 xmlnode_nodeName(const fn_call& fn)
863 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
864 as_value rv;
865 rv.set_null();
867 if (!fn.nargs) {
868 const std::string& val = ptr->nodeName();
869 if ( ! val.empty() ) rv = val;
871 else {
872 ptr->nodeNameSet(fn.arg(0).to_string());
874 return rv;
878 as_value
879 xmlnode_nodeType(const fn_call& fn)
881 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
882 return as_value(ptr->nodeType());
886 as_value
887 xmlnode_attributes(const fn_call& fn)
889 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
891 as_object* attrs = ptr->getAttributes();
892 if (attrs) return as_value(attrs);
893 return as_value();
897 /// Read-only property; evaluates the specified XML object and
898 /// references the first child in the parent node's child
899 /// list. This property is null if the node does not have
900 /// children. This property is undefined if the node is a text
901 /// node. This is a read-only property and cannot be used to
902 /// manipulate child nodes; use the appendChild(), insertBefore(),
903 /// and removeNode() methods to manipulate child nodes.
905 as_value
906 xmlnode_firstChild(const fn_call& fn)
908 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
909 as_value rv;
910 rv.set_null();
912 XMLNode_as* node = ptr->firstChild();
913 if (node) {
914 rv = node->object();
917 return rv;
921 /// Read-only property; an XMLNode as_value that references the last
922 /// child in the node's child list. The XML.lastChild property
923 /// is null if the node does not have children. This property cannot
924 /// be used to manipulate child nodes; use the appendChild(),
925 /// insertBefore(), and removeNode() methods to manipulate child
926 /// nodes.
927 as_value
928 xmlnode_lastChild(const fn_call& fn)
930 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
931 as_value rv;
932 rv.set_null();
934 XMLNode_as* node = ptr->lastChild();
935 if (node) {
936 rv = node->object();
939 return rv;
943 as_value
944 xmlnode_nextSibling(const fn_call& fn)
946 as_value rv;
947 rv.set_null();
949 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
950 XMLNode_as *node = ptr->nextSibling();
951 if (node) {
952 rv = node->object();
954 return rv;
958 as_value
959 xmlnode_previousSibling(const fn_call& fn)
961 as_value rv;
962 rv.set_null();
964 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
965 XMLNode_as *node = ptr->previousSibling();
966 if (node) {
967 rv = node->object();
969 return rv;
973 as_value
974 xmlnode_parentNode(const fn_call& fn)
976 as_value rv;
977 rv.set_null();
979 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
980 XMLNode_as* node = ptr->getParent();
981 if (node) {
982 rv = node->object();
984 return rv;
987 as_value
988 xmlnode_childNodes(const fn_call& fn)
990 XMLNode_as* ptr = ensure<ThisIsNative<XMLNode_as> >(fn);
991 return ptr->childNodes();
995 void
996 enumerateAttributes(const XMLNode_as& node, StringPairs& pairs)
998 pairs.clear();
1000 as_object* obj = node.getAttributes();
1001 if (obj) {
1002 string_table& st = getStringTable(*obj);
1003 SortedPropertyList attrs = enumerateProperties(*obj);
1004 for (SortedPropertyList::const_reverse_iterator i = attrs.rbegin(),
1005 e = attrs.rend(); i != e; ++i) {
1006 // TODO: second argument should take version.
1007 pairs.push_back(
1008 std::make_pair(i->first.toString(st), i->second.to_string()));
1014 /// Return true if this attribute is a namespace specifier and the
1015 /// namespace matches.
1016 bool
1017 namespaceMatches(const StringPairs::value_type& val,
1018 const std::string& ns)
1020 StringNoCaseEqual noCaseCompare;
1021 return (noCaseCompare(val.first.substr(0, 5), "xmlns") &&
1022 noCaseCompare(val.second, ns));
1026 bool
1027 prefixMatches(const StringPairs::value_type& val,
1028 const std::string& prefix)
1030 const std::string& name = val.first;
1031 StringNoCaseEqual noCaseCompare;
1033 // An empty prefix searches for a standard namespace specifier.
1034 // Attributes are stored with no trailing or leading whitespace,
1035 // so a simple comparison should do. TODO: what about "xmlns:"?
1036 if (prefix.empty()) {
1037 return noCaseCompare(name, "xmlns") || noCaseCompare(name, "xmlns:");
1040 if (!noCaseCompare(name.substr(0, 6), "xmlns:")) return false;
1042 return noCaseCompare(prefix, name.substr(6));
1045 } // anonymous namespace
1046 } // gnash namespace
1047 // local Variables:
1048 // mode: C++
1049 // indent-tabs-mode: t
1050 // End: