1 // XMLNode_as.cpp: ActionScript "XMLNode" class, for Gnash.
3 // Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
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.
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
20 #include "XMLNode_as.h"
32 #include "Global_as.h"
33 #include "NativeFunction.h"
34 #include "PropertyList.h"
35 #include "Global_as.h"
38 #include "namedStrings.h"
42 // Function Prototypes
44 typedef std::pair
<std::string
, std::string
> StringPair
;
45 typedef std::vector
<StringPair
> StringPairs
;
46 void enumerateAttributes(const XMLNode_as
& node
,
47 StringPairs
& attributes
);
48 bool prefixMatches(const StringPairs::value_type
& val
,
49 const std::string
& prefix
);
50 bool namespaceMatches(
51 const StringPairs::value_type
& val
,
52 const std::string
& ns
);
54 as_value
xmlnode_new(const fn_call
& fn
);
55 as_value
xmlnode_nodeName(const fn_call
& fn
);
56 as_value
xmlnode_nodeValue(const fn_call
& fn
);
57 as_value
xmlnode_nodeType(const fn_call
& fn
);
58 as_value
xmlnode_attributes(const fn_call
& fn
);
59 as_value
xmlnode_appendChild(const fn_call
& fn
);
60 as_value
xmlnode_cloneNode(const fn_call
& fn
);
61 as_value
xmlnode_lastChild(const fn_call
& fn
);
62 as_value
xmlnode_firstChild(const fn_call
& fn
);
63 as_value
xmlnode_nextSibling(const fn_call
& fn
);
64 as_value
xmlnode_childNodes(const fn_call
& fn
);
65 as_value
xmlnode_previousSibling(const fn_call
& fn
);
66 as_value
xmlnode_parentNode(const fn_call
& fn
);
67 as_value
xmlnode_getNamespaceForPrefix(const fn_call
& fn
);
68 as_value
xmlnode_getPrefixForNamespace(const fn_call
& fn
);
69 as_value
xmlnode_namespaceURI(const fn_call
& fn
);
70 as_value
xmlnode_hasChildNodes(const fn_call
& fn
);
71 as_value
xmlnode_insertBefore(const fn_call
& fn
);
72 as_value
xmlnode_removeNode(const fn_call
& fn
);
73 as_value
xmlnode_toString(const fn_call
& fn
);
74 as_value
xmlnode_localName(const fn_call
& fn
);
75 as_value
xmlnode_prefix(const fn_call
& fn
);
76 void attachXMLNodeInterface(as_object
& o
);
79 XMLNode_as::XMLNode_as(Global_as
& gl
)
84 _attributes(new as_object(gl
)),
90 XMLNode_as::XMLNode_as(const XMLNode_as
& tpl
, bool deep
)
95 _attributes(new as_object(_global
)),
101 // only clone children if in deep mode
103 const Children
& from
=tpl
._children
;
104 for (const auto& child
: from
) {
105 XMLNode_as
* copy
= new XMLNode_as(*child
, deep
);
106 copy
->setParent(this);
107 _children
.push_back(copy
);
112 XMLNode_as::~XMLNode_as()
114 // In practice it is quite likely that the child will be garbage-collected
115 // before the parent. See Savannah bug #39404.
117 // NOTE: do not removeChild as it makes too much
118 // noise including calls to string_table
119 // (due to updateChildNodes)
120 // See https://savannah.gnu.org/bugs/?40439
121 _parent
->_children
.remove(this);
132 // This is almost the same as if the XMLNode constructor were called,
133 // but not quite. There is no __constructor__ property, and when we
134 // override _global.XMLNode, we can show that it is not called.
136 as_object
* o
= createObject(_global
);
138 toObject(getMember(_global
, NSV::CLASS_XMLNODE
), getVM(_global
));
140 o
->set_prototype(getMember(*xn
, NSV::PROP_PROTOTYPE
));
141 o
->init_member(NSV::PROP_CONSTRUCTOR
, xn
);
150 XMLNode_as::updateChildNodes()
152 if (!_childNodes
) return;
154 // Clear array of all elements.
155 _childNodes
->set_member(NSV::PROP_LENGTH
, 0.0);
157 if (_children
.empty()) return;
159 VM
& vm
= getVM(_global
);
161 // Set up the array without calling push()!
162 const size_t size
= _children
.size();
163 Children::const_iterator it
= _children
.begin();
164 for (size_t i
= 0; i
!= size
; ++i
, ++it
) {
165 XMLNode_as
* node
= *it
;
166 const ObjectURI
& key
= arrayKey(vm
, i
);
167 _childNodes
->set_member(key
, node
->object());
169 // All elements are set to readonly.
170 _childNodes
->set_member_flags(key
, PropFlags::readOnly
);
175 XMLNode_as::childNodes()
178 _childNodes
= _global
.createArray();
185 XMLNode_as::hasChildNodes() const
187 return !_children
.empty();
191 XMLNode_as::firstChild() const
193 if (_children
.empty()) return nullptr;
194 return _children
.front();
198 XMLNode_as::cloneNode(bool deep
) const
200 XMLNode_as
* newnode
= new XMLNode_as(*this, deep
);
205 XMLNode_as::lastChild() const
207 if (_children
.empty()) {
210 return _children
.back();
214 XMLNode_as::removeChild(XMLNode_as
* node
)
216 node
->setParent(nullptr);
217 _children
.remove(node
);
222 XMLNode_as::appendChild(XMLNode_as
* node
)
225 node
->setParent(this);
226 _children
.push_back(node
);
231 XMLNode_as::descendsFrom(XMLNode_as
* node
) const
236 XMLNode_as
* parent
= getParent();
238 return parent
->descendsFrom(node
);
245 XMLNode_as::insertBefore(XMLNode_as
* newnode
, XMLNode_as
* pos
)
249 // find iterator for positional parameter
250 Children::iterator it
= std::find(_children
.begin(), _children
.end(), pos
);
251 if (it
== _children
.end()) {
252 IF_VERBOSE_ASCODING_ERRORS(
253 log_aserror(_("XMLNode.insertBefore(): positional parameter "
254 "is not a child of this node"));
259 _children
.insert(it
, newnode
);
261 XMLNode_as
* parent
= newnode
->getParent();
263 parent
->removeChild(newnode
);
266 newnode
->setParent(this);
271 XMLNode_as::previousSibling() const
273 if (!_parent
) return nullptr;
274 if (_parent
->_children
.size() <= 1) return nullptr;
276 XMLNode_as
*previous_node
= nullptr;
277 for (XMLNode_as
* child
: _parent
->_children
) {
279 if (child
== this) return previous_node
;
281 previous_node
= child
;
288 XMLNode_as::nextSibling() const
291 if (!_parent
) return nullptr;
293 if (_parent
->_children
.size() <= 1) return nullptr;
295 XMLNode_as
*previous_node
= nullptr;
296 for (Children::reverse_iterator itx
= _parent
->_children
.rbegin();
297 itx
!= _parent
->_children
.rend(); ++itx
) {
299 if (*itx
== this) return previous_node
;
300 previous_node
= *itx
;
307 XMLNode_as::toString(std::ostream
& xmlout
, bool encode
) const
309 stringify(*this, xmlout
, encode
);
313 XMLNode_as::setAttribute(const std::string
& name
, const std::string
& value
)
316 VM
& vm
= getVM(_global
);
317 _attributes
->set_member(getURI(vm
, name
), value
);
322 XMLNode_as::getPrefixForNamespace(const std::string
& ns
, std::string
& prefix
)
325 const XMLNode_as
* node
= this;
326 StringPairs::const_iterator it
;
330 enumerateAttributes(*node
, attrs
);
333 it
= std::find_if(attrs
.begin(), attrs
.end(),
334 std::bind(namespaceMatches
, std::placeholders::_1
, ns
));
335 if (it
!= attrs
.end()) break;
337 node
= node
->getParent();
341 if (!node
) return false;
343 // Return the matching prefix
344 const std::string
& name
= it
->first
;
346 if (name
.length() == 5) {
350 assert (name
.length() >= 6);
352 if (name
[5] != ':') return false;
354 // Can also be empty.
355 prefix
= name
.substr(6);
360 XMLNode_as::getNamespaceForPrefix(const std::string
& prefix
, std::string
& ns
)
363 const XMLNode_as
* node
= this;
364 StringPairs::const_iterator it
;
369 enumerateAttributes(*node
, attrs
);
371 if (!attrs
.empty()) {
373 it
= std::find_if(attrs
.begin(), attrs
.end(),
374 std::bind(prefixMatches
, std::placeholders::_1
, prefix
));
375 if (it
!= attrs
.end()) break;
377 node
= node
->getParent();
380 // None found; return undefined
383 // Return the matching namespace
389 XMLNode_as::extractPrefix(std::string
& prefix
) const
392 if (_name
.empty()) return false;
394 std::string::size_type pos
= _name
.find(':');
395 if (pos
== std::string::npos
|| pos
== _name
.size() - 1) {
399 prefix
= _name
.substr(0, pos
);
404 XMLNode_as::clearChildren()
406 for (XMLNode_as
* node
: _children
) {
408 node
->setParent(nullptr);
409 if (!node
->_object
) {
410 // The node is not GC'd because it has no associated object.
411 // See XMLNode_as class docs.
417 // Reset so that it is reinitialized on next access.
418 _childNodes
= nullptr;
422 XMLNode_as::stringify(const XMLNode_as
& xml
, std::ostream
& xmlout
, bool encode
)
425 const std::string
& nodeValue
= xml
.nodeValue();
426 const std::string
& nodeName
= xml
.nodeName();
427 NodeType type
= xml
.nodeType();
430 log_debug("Stringifying node %p with name %s, as_value %s, %u "
431 "attributes and %u children", (void*)&xml
, nodeName
,
432 nodeValue
, xml
._attributes
.size(), xml
._children
.size());
435 if (!nodeName
.empty() || type
== Element
) {
437 xmlout
<< "<" << nodeName
;
439 // Process the attributes, if any
441 enumerateAttributes(xml
, attrs
);
442 if (!attrs
.empty()) {
444 for (auto& attr
: attrs
) {
445 escapeXML(attr
.second
);
446 xmlout
<< " " << attr
.first
<< "=\"" << attr
.second
<< "\"";
450 // If the node has no content, just close the tag now
451 if (nodeValue
.empty() && xml
._children
.empty()) {
456 // Will use a closing tag later
461 // Node as_value first, then children
464 Global_as
& gl
= xml
._global
;
467 std::string
escaped(nodeValue
);
469 const std::string
& val
= encode
?
470 callMethod(&gl
, NSV::PROP_ESCAPE
, escaped
).to_string() :
476 // Childs, after node as_value.
477 for (XMLNode_as
* child
: xml
._children
) {
479 child
->toString(xmlout
, encode
);
482 if (!nodeName
.empty() || type
== Element
) {
483 xmlout
<< "</" << nodeName
<< ">";
488 XMLNode_as::setReachable()
490 // If there is a parent, make sure its object is reachable. This goes
491 // up towards the root node of tree without marking the XMLNode
492 // resources (which would cause infinite recursion).
493 if (_parent
&& _parent
->_object
) _parent
->_object
->setReachable();
496 std::for_each(_children
.begin(), _children
.end(),
497 std::mem_fn(&XMLNode_as::setReachable
));
499 // Mark attributes object
500 if (_attributes
) _attributes
->setReachable();
502 if (_object
) _object
->setReachable();
504 if (_childNodes
) _childNodes
->setReachable();
508 registerXMLNodeNative(as_object
& where
)
510 VM
& vm
= getVM(where
);
511 vm
.registerNative(xmlnode_cloneNode
, 253, 1);
512 vm
.registerNative(xmlnode_removeNode
, 253, 2);
513 vm
.registerNative(xmlnode_insertBefore
, 253, 3);
514 vm
.registerNative(xmlnode_appendChild
, 253, 4);
515 vm
.registerNative(xmlnode_hasChildNodes
, 253, 5);
516 vm
.registerNative(xmlnode_toString
, 253, 6);
517 vm
.registerNative(xmlnode_getNamespaceForPrefix
, 253, 7);
518 vm
.registerNative(xmlnode_getPrefixForNamespace
, 253, 8);
522 xmlnode_class_init(as_object
& where
, const ObjectURI
& uri
)
524 Global_as
& gl
= getGlobal(where
);
525 as_object
* proto
= createObject(gl
);
526 attachXMLNodeInterface(*proto
);
527 as_object
* cl
= gl
.createClass(&xmlnode_new
, proto
);
529 where
.init_member(uri
, cl
, as_object::DefaultFlags
);
536 attachXMLNodeInterface(as_object
& o
)
541 const int noFlags
= 0;
544 o
.init_member("cloneNode", vm
.getNative(253, 1), noFlags
);
545 o
.init_member("removeNode", vm
.getNative(253, 2), noFlags
);
546 o
.init_member("insertBefore", vm
.getNative(253, 3), noFlags
);
547 o
.init_member("appendChild", vm
.getNative(253, 4), noFlags
);
548 o
.init_member("hasChildNodes", vm
.getNative(253, 5), noFlags
);
549 o
.init_member("toString", vm
.getNative(253, 6), noFlags
);
550 o
.init_member("getNamespaceForPrefix", vm
.getNative(253, 7), noFlags
);
551 o
.init_member("getPrefixForNamespace", vm
.getNative(253, 8), noFlags
);
553 const int protectedFlags
= 0;
555 // Just the protected flag:
557 o
.init_readonly_property("attributes", &xmlnode_attributes
, protectedFlags
);
558 o
.init_readonly_property("childNodes", &xmlnode_childNodes
, protectedFlags
);
559 o
.init_readonly_property("firstChild", &xmlnode_firstChild
, protectedFlags
);
560 o
.init_readonly_property("lastChild", &xmlnode_lastChild
, protectedFlags
);
561 o
.init_readonly_property("nextSibling",
562 &xmlnode_nextSibling
, protectedFlags
);
563 o
.init_property("nodeName", &xmlnode_nodeName
,
564 &xmlnode_nodeName
, protectedFlags
);
565 o
.init_readonly_property("nodeType", &xmlnode_nodeType
, protectedFlags
);
566 o
.init_property("nodeValue", &xmlnode_nodeValue
,
567 &xmlnode_nodeValue
, protectedFlags
);
568 o
.init_readonly_property("parentNode", &xmlnode_parentNode
, protectedFlags
);
569 o
.init_readonly_property("previousSibling",
570 &xmlnode_previousSibling
, protectedFlags
);
571 o
.init_readonly_property("prefix", &xmlnode_prefix
, protectedFlags
);
572 o
.init_readonly_property("localName", &xmlnode_localName
, protectedFlags
);
573 o
.init_readonly_property("namespaceURI",
574 &xmlnode_namespaceURI
, protectedFlags
);
579 xmlnode_new(const fn_call
& fn
)
582 as_object
* obj
= ensure
<ValidThis
>(fn
);
588 std::unique_ptr
<XMLNode_as
> xml(new XMLNode_as(getGlobal(fn
)));
589 xml
->nodeTypeSet(XMLNode_as::NodeType(toInt(fn
.arg(0), getVM(fn
))));
592 const std::string
& str
= fn
.arg(1).to_string();
593 switch (xml
->nodeType())
595 case XMLNode_as::Element
:
596 xml
->nodeNameSet(str
);
599 xml
->nodeValueSet(str
);
604 // This sets the relay!
606 obj
->setRelay(xml
.release());
613 xmlnode_appendChild(const fn_call
& fn
)
616 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
619 IF_VERBOSE_ASCODING_ERRORS(
620 log_aserror(_("XMLNode::appendChild() needs at least one "
627 if (!isNativeType(toObject(fn
.arg(0), getVM(fn
)), node
)) {
628 IF_VERBOSE_ASCODING_ERRORS(
629 log_aserror(_("First argument to XMLNode::appendChild() is not "
635 if (ptr
->descendsFrom(node
)) {
636 IF_VERBOSE_ASCODING_ERRORS(
637 log_aserror(_("XMLNode.appendChild(): attempted to move a node to "
638 "among its own descendants."));
643 XMLNode_as
* parent
= node
->getParent();
645 parent
->removeChild(node
);
647 ptr
->appendChild(node
);
654 xmlnode_cloneNode(const fn_call
& fn
)
656 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
659 if (fn
.nargs
> 0) deep
= toBool(fn
.arg(0), getVM(fn
));
661 as_object
* newnode
= ptr
->cloneNode(deep
)->object();
662 return as_value(newnode
);
667 xmlnode_insertBefore(const fn_call
& fn
)
669 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
673 IF_VERBOSE_ASCODING_ERRORS(
674 std::stringstream ss
; fn
.dump_args(ss
);
675 log_aserror(_("XMLNode.insertBefore(%s) needs at least two "
676 "arguments"), ss
.str());
683 if (!isNativeType(toObject(fn
.arg(0), getVM(fn
)), newnode
)) {
684 IF_VERBOSE_ASCODING_ERRORS(
685 std::stringstream ss
; fn
.dump_args(ss
);
686 log_aserror(_("First argument to XMLNode.insertBefore(%s) is not "
687 "an XMLNode"), ss
.str());
694 if (!isNativeType(toObject(fn
.arg(1), getVM(fn
)), pos
)) {
695 IF_VERBOSE_ASCODING_ERRORS(
696 std::stringstream ss
; fn
.dump_args(ss
);
697 log_aserror(_("Second argument to XMLNode.insertBefore(%s) is not "
698 "an XMLNode"), ss
.str());
703 if (pos
->descendsFrom(newnode
)) {
704 IF_VERBOSE_ASCODING_ERRORS(
705 log_aserror(_("XMLNode.insertBefore(): attempted to move a node to "
706 "among its own descendants."));
711 ptr
->insertBefore(newnode
, pos
);
718 xmlnode_getNamespaceForPrefix(const fn_call
& fn
)
720 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
727 ptr
->getNamespaceForPrefix(fn
.arg(0).to_string(), ns
);
728 if (ns
.empty()) return as_value();
734 xmlnode_getPrefixForNamespace(const fn_call
& fn
)
736 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
743 // Return undefined if none found; otherwise the prefix string found.
744 // This can be empty if it is a standard namespace.
745 if (!ptr
->getPrefixForNamespace(fn
.arg(0).to_string(), prefix
)) {
748 return as_value(prefix
);
751 /// If the node has a prefix, return the matching namespace. Otherwise,
752 /// returns a namespaceURI set with the xmlns attribute, searching upwards
753 /// through parent nodes if necessary.
755 /// This standard namespace can only be set during XML parsing and cannot
756 /// be changed or set using attributes.
758 /// Conversely, the similar getNamespaceForPrefix("") can be set and changed
759 /// through attributes.
761 xmlnode_namespaceURI(const fn_call
& fn
)
763 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
765 // Read-only property
767 const std::string
& name
= ptr
->nodeName();
776 if (ptr
->extractPrefix(prefix
)) {
778 ptr
->getNamespaceForPrefix(prefix
, ns
);
782 // Search recursively for a namespace. Return an empty string
784 XMLNode_as
* node
= ptr
;
785 while (node
&& node
->getNamespaceURI().empty()) {
786 node
= node
->getParent();
788 if (!node
) return as_value("");
790 return as_value(node
->getNamespaceURI());
794 // Return the prefix part of the node name. If there is no colon, or one
795 // colon at the end of the string, this is empty. Otherwise it is the part
796 // up to the first colon.
798 xmlnode_prefix(const fn_call
& fn
)
800 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
802 // Read-only property
804 if (ptr
->nodeName().empty()) {
811 if (!ptr
->extractPrefix(prefix
)) return as_value("");
812 return as_value(prefix
);
816 // The local part of a node name. If there is no colon or a single colon
817 // at the end of the string, this is the whole string. Otherwise all of the
818 // string after the first colon.
820 xmlnode_localName(const fn_call
& fn
)
822 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
824 // Read-only property
826 if (ptr
->nodeName().empty()) {
832 const std::string
& nodeName
= ptr
->nodeName();
833 if (nodeName
.empty()) return as_value("");
835 std::string::size_type pos
= nodeName
.find(':');
836 if (pos
== std::string::npos
|| pos
== nodeName
.size() - 1) {
837 return as_value(nodeName
);
840 return as_value(nodeName
.substr(pos
+ 1));
845 xmlnode_removeNode(const fn_call
& fn
)
847 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
849 XMLNode_as
* parent
= ptr
->getParent();
850 if (parent
) parent
->removeChild(ptr
);
856 xmlnode_toString(const fn_call
& fn
)
859 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
861 std::stringstream ss
;
864 return as_value(ss
.str());
869 xmlnode_hasChildNodes(const fn_call
& fn
)
871 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
872 return as_value(ptr
->hasChildNodes());
877 xmlnode_nodeValue(const fn_call
& fn
)
879 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
885 const std::string
& val
= ptr
->nodeValue();
886 if ( ! val
.empty() ) rv
= val
;
890 ptr
->nodeValueSet(fn
.arg(0).to_string());
897 xmlnode_nodeName(const fn_call
& fn
)
899 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
904 const std::string
& val
= ptr
->nodeName();
905 if ( ! val
.empty() ) rv
= val
;
908 ptr
->nodeNameSet(fn
.arg(0).to_string());
915 xmlnode_nodeType(const fn_call
& fn
)
917 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
918 return as_value(ptr
->nodeType());
923 xmlnode_attributes(const fn_call
& fn
)
925 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
927 as_object
* attrs
= ptr
->getAttributes();
928 if (attrs
) return as_value(attrs
);
933 /// Read-only property; evaluates the specified XML object and
934 /// references the first child in the parent node's child
935 /// list. This property is null if the node does not have
936 /// children. This property is undefined if the node is a text
937 /// node. This is a read-only property and cannot be used to
938 /// manipulate child nodes; use the appendChild(), insertBefore(),
939 /// and removeNode() methods to manipulate child nodes.
942 xmlnode_firstChild(const fn_call
& fn
)
944 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
948 XMLNode_as
* node
= ptr
->firstChild();
957 /// Read-only property; an XMLNode as_value that references the last
958 /// child in the node's child list. The XML.lastChild property
959 /// is null if the node does not have children. This property cannot
960 /// be used to manipulate child nodes; use the appendChild(),
961 /// insertBefore(), and removeNode() methods to manipulate child
964 xmlnode_lastChild(const fn_call
& fn
)
966 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
970 XMLNode_as
* node
= ptr
->lastChild();
980 xmlnode_nextSibling(const fn_call
& fn
)
985 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
986 XMLNode_as
*node
= ptr
->nextSibling();
995 xmlnode_previousSibling(const fn_call
& fn
)
1000 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
1001 XMLNode_as
*node
= ptr
->previousSibling();
1003 rv
= node
->object();
1010 xmlnode_parentNode(const fn_call
& fn
)
1015 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
1016 XMLNode_as
* node
= ptr
->getParent();
1018 rv
= node
->object();
1024 xmlnode_childNodes(const fn_call
& fn
)
1026 XMLNode_as
* ptr
= ensure
<ThisIsNative
<XMLNode_as
> >(fn
);
1027 return ptr
->childNodes();
1032 enumerateAttributes(const XMLNode_as
& node
, StringPairs
& pairs
)
1036 as_object
* obj
= node
.getAttributes();
1038 string_table
& st
= getStringTable(*obj
);
1039 SortedPropertyList attrs
= enumerateProperties(*obj
);
1040 for (SortedPropertyList::const_reverse_iterator i
= attrs
.rbegin(),
1041 e
= attrs
.rend(); i
!= e
; ++i
) {
1042 // TODO: second argument should take version.
1044 std::make_pair(i
->first
.toString(st
), i
->second
.to_string()));
1050 /// Return true if this attribute is a namespace specifier and the
1051 /// namespace matches.
1053 namespaceMatches(const StringPairs::value_type
& val
,
1054 const std::string
& ns
)
1056 StringNoCaseEqual noCaseCompare
;
1057 return (noCaseCompare(val
.first
.substr(0, 5), "xmlns") &&
1058 noCaseCompare(val
.second
, ns
));
1063 prefixMatches(const StringPairs::value_type
& val
,
1064 const std::string
& prefix
)
1066 const std::string
& name
= val
.first
;
1067 StringNoCaseEqual noCaseCompare
;
1069 // An empty prefix searches for a standard namespace specifier.
1070 // Attributes are stored with no trailing or leading whitespace,
1071 // so a simple comparison should do. TODO: what about "xmlns:"?
1072 if (prefix
.empty()) {
1073 return noCaseCompare(name
, "xmlns") || noCaseCompare(name
, "xmlns:");
1076 if (!noCaseCompare(name
.substr(0, 6), "xmlns:")) return false;
1078 return noCaseCompare(prefix
, name
.substr(6));
1081 } // anonymous namespace
1082 } // gnash namespace
1085 // indent-tabs-mode: t