xref: /reactos/dll/win32/msxml3/attribute.c (revision 8361200d)
1 /*
2  *    DOM Attribute implementation
3  *
4  * Copyright 2006 Huw Davies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20 
21 #define COBJMACROS
22 
23 #include "config.h"
24 
25 #include <stdarg.h>
26 #ifdef HAVE_LIBXML2
27 # include <libxml/parser.h>
28 # include <libxml/xmlerror.h>
29 # include <libxml/HTMLtree.h>
30 #endif
31 
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winuser.h"
35 #include "ole2.h"
36 #include "msxml6.h"
37 
38 #include "msxml_private.h"
39 
40 #include "wine/debug.h"
41 
42 #ifdef HAVE_LIBXML2
43 
44 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
45 
46 static const xmlChar xmlns[] = "xmlns";
47 
48 typedef struct _domattr
49 {
50     xmlnode node;
51     IXMLDOMAttribute IXMLDOMAttribute_iface;
52     LONG ref;
53 } domattr;
54 
55 static const tid_t domattr_se_tids[] = {
56     IXMLDOMNode_tid,
57     IXMLDOMAttribute_tid,
58     NULL_tid
59 };
60 
61 static inline domattr *impl_from_IXMLDOMAttribute( IXMLDOMAttribute *iface )
62 {
63     return CONTAINING_RECORD(iface, domattr, IXMLDOMAttribute_iface);
64 }
65 
66 static HRESULT WINAPI domattr_QueryInterface(
67     IXMLDOMAttribute *iface,
68     REFIID riid,
69     void** ppvObject )
70 {
71     domattr *This = impl_from_IXMLDOMAttribute( iface );
72     TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
73 
74     if ( IsEqualGUID( riid, &IID_IXMLDOMAttribute ) ||
75          IsEqualGUID( riid, &IID_IXMLDOMNode ) ||
76          IsEqualGUID( riid, &IID_IDispatch ) ||
77          IsEqualGUID( riid, &IID_IUnknown ) )
78     {
79         *ppvObject = iface;
80     }
81     else if(node_query_interface(&This->node, riid, ppvObject))
82     {
83         return *ppvObject ? S_OK : E_NOINTERFACE;
84     }
85     else if(IsEqualGUID( riid, &IID_ISupportErrorInfo ))
86     {
87         return node_create_supporterrorinfo(domattr_se_tids, ppvObject);
88     }
89     else
90     {
91         TRACE("Unsupported interface %s\n", debugstr_guid(riid));
92         *ppvObject = NULL;
93         return E_NOINTERFACE;
94     }
95 
96     IXMLDOMAttribute_AddRef(iface);
97     return S_OK;
98 }
99 
100 static ULONG WINAPI domattr_AddRef(
101     IXMLDOMAttribute *iface )
102 {
103     domattr *This = impl_from_IXMLDOMAttribute( iface );
104     ULONG ref = InterlockedIncrement( &This->ref );
105     TRACE("(%p)->(%d)\n", This, ref);
106     return ref;
107 }
108 
109 static ULONG WINAPI domattr_Release(
110     IXMLDOMAttribute *iface )
111 {
112     domattr *This = impl_from_IXMLDOMAttribute( iface );
113     ULONG ref = InterlockedDecrement( &This->ref );
114 
115     TRACE("(%p)->(%d)\n", This, ref);
116     if ( ref == 0 )
117     {
118         destroy_xmlnode(&This->node);
119         heap_free( This );
120     }
121 
122     return ref;
123 }
124 
125 static HRESULT WINAPI domattr_GetTypeInfoCount(
126     IXMLDOMAttribute *iface,
127     UINT* pctinfo )
128 {
129     domattr *This = impl_from_IXMLDOMAttribute( iface );
130     return IDispatchEx_GetTypeInfoCount(&This->node.dispex.IDispatchEx_iface, pctinfo);
131 }
132 
133 static HRESULT WINAPI domattr_GetTypeInfo(
134     IXMLDOMAttribute *iface,
135     UINT iTInfo, LCID lcid,
136     ITypeInfo** ppTInfo )
137 {
138     domattr *This = impl_from_IXMLDOMAttribute( iface );
139     return IDispatchEx_GetTypeInfo(&This->node.dispex.IDispatchEx_iface,
140         iTInfo, lcid, ppTInfo);
141 }
142 
143 static HRESULT WINAPI domattr_GetIDsOfNames(
144     IXMLDOMAttribute *iface,
145     REFIID riid, LPOLESTR* rgszNames,
146     UINT cNames, LCID lcid, DISPID* rgDispId )
147 {
148     domattr *This = impl_from_IXMLDOMAttribute( iface );
149     return IDispatchEx_GetIDsOfNames(&This->node.dispex.IDispatchEx_iface,
150         riid, rgszNames, cNames, lcid, rgDispId);
151 }
152 
153 static HRESULT WINAPI domattr_Invoke(
154     IXMLDOMAttribute *iface,
155     DISPID dispIdMember, REFIID riid, LCID lcid,
156     WORD wFlags, DISPPARAMS* pDispParams, VARIANT* pVarResult,
157     EXCEPINFO* pExcepInfo, UINT* puArgErr )
158 {
159     domattr *This = impl_from_IXMLDOMAttribute( iface );
160     return IDispatchEx_Invoke(&This->node.dispex.IDispatchEx_iface,
161         dispIdMember, riid, lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
162 }
163 
164 static HRESULT WINAPI domattr_get_nodeName(
165     IXMLDOMAttribute *iface,
166     BSTR* p )
167 {
168     domattr *This = impl_from_IXMLDOMAttribute( iface );
169 
170     TRACE("(%p)->(%p)\n", This, p);
171 
172     return node_get_nodeName(&This->node, p);
173 }
174 
175 static HRESULT WINAPI domattr_get_nodeValue(
176     IXMLDOMAttribute *iface,
177     VARIANT* value)
178 {
179     domattr *This = impl_from_IXMLDOMAttribute( iface );
180 
181     TRACE("(%p)->(%p)\n", This, value);
182 
183     return node_get_content(&This->node, value);
184 }
185 
186 static HRESULT WINAPI domattr_put_nodeValue(
187     IXMLDOMAttribute *iface,
188     VARIANT value)
189 {
190     domattr *This = impl_from_IXMLDOMAttribute( iface );
191 
192     TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
193 
194     return node_put_value_escaped(&This->node, &value);
195 }
196 
197 static HRESULT WINAPI domattr_get_nodeType(
198     IXMLDOMAttribute *iface,
199     DOMNodeType* domNodeType )
200 {
201     domattr *This = impl_from_IXMLDOMAttribute( iface );
202 
203     TRACE("(%p)->(%p)\n", This, domNodeType);
204 
205     *domNodeType = NODE_ATTRIBUTE;
206     return S_OK;
207 }
208 
209 static HRESULT WINAPI domattr_get_parentNode(
210     IXMLDOMAttribute *iface,
211     IXMLDOMNode** parent )
212 {
213     domattr *This = impl_from_IXMLDOMAttribute( iface );
214     TRACE("(%p)->(%p)\n", This, parent);
215     if (!parent) return E_INVALIDARG;
216     *parent = NULL;
217     return S_FALSE;
218 }
219 
220 static HRESULT WINAPI domattr_get_childNodes(
221     IXMLDOMAttribute *iface,
222     IXMLDOMNodeList** outList)
223 {
224     domattr *This = impl_from_IXMLDOMAttribute( iface );
225 
226     TRACE("(%p)->(%p)\n", This, outList);
227 
228     return node_get_child_nodes(&This->node, outList);
229 }
230 
231 static HRESULT WINAPI domattr_get_firstChild(
232     IXMLDOMAttribute *iface,
233     IXMLDOMNode** domNode)
234 {
235     domattr *This = impl_from_IXMLDOMAttribute( iface );
236 
237     TRACE("(%p)->(%p)\n", This, domNode);
238 
239     return node_get_first_child(&This->node, domNode);
240 }
241 
242 static HRESULT WINAPI domattr_get_lastChild(
243     IXMLDOMAttribute *iface,
244     IXMLDOMNode** domNode)
245 {
246     domattr *This = impl_from_IXMLDOMAttribute( iface );
247 
248     TRACE("(%p)->(%p)\n", This, domNode);
249 
250     return node_get_last_child(&This->node, domNode);
251 }
252 
253 static HRESULT WINAPI domattr_get_previousSibling(
254     IXMLDOMAttribute *iface,
255     IXMLDOMNode** domNode)
256 {
257     domattr *This = impl_from_IXMLDOMAttribute( iface );
258 
259     TRACE("(%p)->(%p)\n", This, domNode);
260 
261     return return_null_node(domNode);
262 }
263 
264 static HRESULT WINAPI domattr_get_nextSibling(
265     IXMLDOMAttribute *iface,
266     IXMLDOMNode** domNode)
267 {
268     domattr *This = impl_from_IXMLDOMAttribute( iface );
269 
270     TRACE("(%p)->(%p)\n", This, domNode);
271 
272     return return_null_node(domNode);
273 }
274 
275 static HRESULT WINAPI domattr_get_attributes(
276     IXMLDOMAttribute *iface,
277     IXMLDOMNamedNodeMap** attributeMap)
278 {
279     domattr *This = impl_from_IXMLDOMAttribute( iface );
280 
281     TRACE("(%p)->(%p)\n", This, attributeMap);
282 
283     return return_null_ptr((void**)attributeMap);
284 }
285 
286 static HRESULT WINAPI domattr_insertBefore(
287     IXMLDOMAttribute *iface,
288     IXMLDOMNode* newNode, VARIANT refChild,
289     IXMLDOMNode** old_node)
290 {
291     domattr *This = impl_from_IXMLDOMAttribute( iface );
292     DOMNodeType type;
293     HRESULT hr;
294 
295     FIXME("(%p)->(%p %s %p) needs test\n", This, newNode, debugstr_variant(&refChild), old_node);
296 
297     if (!newNode) return E_INVALIDARG;
298 
299     hr = IXMLDOMNode_get_nodeType(newNode, &type);
300     if (hr != S_OK) return hr;
301 
302     TRACE("new node type %d\n", type);
303     switch (type)
304     {
305         case NODE_ATTRIBUTE:
306         case NODE_CDATA_SECTION:
307         case NODE_COMMENT:
308         case NODE_ELEMENT:
309         case NODE_PROCESSING_INSTRUCTION:
310             if (old_node) *old_node = NULL;
311             return E_FAIL;
312         default:
313             return node_insert_before(&This->node, newNode, &refChild, old_node);
314     }
315 }
316 
317 static HRESULT WINAPI domattr_replaceChild(
318     IXMLDOMAttribute *iface,
319     IXMLDOMNode* newNode,
320     IXMLDOMNode* oldNode,
321     IXMLDOMNode** outOldNode)
322 {
323     domattr *This = impl_from_IXMLDOMAttribute( iface );
324 
325     FIXME("(%p)->(%p %p %p) needs tests\n", This, newNode, oldNode, outOldNode);
326 
327     return node_replace_child(&This->node, newNode, oldNode, outOldNode);
328 }
329 
330 static HRESULT WINAPI domattr_removeChild(
331     IXMLDOMAttribute *iface,
332     IXMLDOMNode *child, IXMLDOMNode **oldChild)
333 {
334     domattr *This = impl_from_IXMLDOMAttribute( iface );
335     TRACE("(%p)->(%p %p)\n", This, child, oldChild);
336     return node_remove_child(&This->node, child, oldChild);
337 }
338 
339 static HRESULT WINAPI domattr_appendChild(
340     IXMLDOMAttribute *iface,
341     IXMLDOMNode *child, IXMLDOMNode **outChild)
342 {
343     domattr *This = impl_from_IXMLDOMAttribute( iface );
344     TRACE("(%p)->(%p %p)\n", This, child, outChild);
345     return node_append_child(&This->node, child, outChild);
346 }
347 
348 static HRESULT WINAPI domattr_hasChildNodes(
349     IXMLDOMAttribute *iface,
350     VARIANT_BOOL *ret)
351 {
352     domattr *This = impl_from_IXMLDOMAttribute( iface );
353     TRACE("(%p)->(%p)\n", This, ret);
354     return node_has_childnodes(&This->node, ret);
355 }
356 
357 static HRESULT WINAPI domattr_get_ownerDocument(
358     IXMLDOMAttribute *iface,
359     IXMLDOMDocument **doc)
360 {
361     domattr *This = impl_from_IXMLDOMAttribute( iface );
362     TRACE("(%p)->(%p)\n", This, doc);
363     return node_get_owner_doc(&This->node, doc);
364 }
365 
366 static HRESULT WINAPI domattr_cloneNode(
367     IXMLDOMAttribute *iface,
368     VARIANT_BOOL deep, IXMLDOMNode** outNode)
369 {
370     domattr *This = impl_from_IXMLDOMAttribute( iface );
371     TRACE("(%p)->(%d %p)\n", This, deep, outNode);
372     return node_clone( &This->node, deep, outNode );
373 }
374 
375 static HRESULT WINAPI domattr_get_nodeTypeString(
376     IXMLDOMAttribute *iface,
377     BSTR* p)
378 {
379     domattr *This = impl_from_IXMLDOMAttribute( iface );
380     static const WCHAR attributeW[] = {'a','t','t','r','i','b','u','t','e',0};
381 
382     TRACE("(%p)->(%p)\n", This, p);
383 
384     return return_bstr(attributeW, p);
385 }
386 
387 static HRESULT WINAPI domattr_get_text(
388     IXMLDOMAttribute *iface,
389     BSTR* p)
390 {
391     domattr *This = impl_from_IXMLDOMAttribute( iface );
392     TRACE("(%p)->(%p)\n", This, p);
393     return node_get_text(&This->node, p);
394 }
395 
396 static HRESULT WINAPI domattr_put_text(
397     IXMLDOMAttribute *iface,
398     BSTR p)
399 {
400     domattr *This = impl_from_IXMLDOMAttribute( iface );
401     TRACE("(%p)->(%s)\n", This, debugstr_w(p));
402     return node_put_text( &This->node, p );
403 }
404 
405 static HRESULT WINAPI domattr_get_specified(
406     IXMLDOMAttribute *iface,
407     VARIANT_BOOL* isSpecified)
408 {
409     domattr *This = impl_from_IXMLDOMAttribute( iface );
410     FIXME("(%p)->(%p) stub!\n", This, isSpecified);
411     *isSpecified = VARIANT_TRUE;
412     return S_OK;
413 }
414 
415 static HRESULT WINAPI domattr_get_definition(
416     IXMLDOMAttribute *iface,
417     IXMLDOMNode** definitionNode)
418 {
419     domattr *This = impl_from_IXMLDOMAttribute( iface );
420     FIXME("(%p)->(%p)\n", This, definitionNode);
421     return E_NOTIMPL;
422 }
423 
424 static HRESULT WINAPI domattr_get_nodeTypedValue(
425     IXMLDOMAttribute *iface,
426     VARIANT* value)
427 {
428     domattr *This = impl_from_IXMLDOMAttribute( iface );
429     IXMLDOMDocument *doc;
430     HRESULT hr;
431 
432     TRACE("(%p)->(%p)\n", This, value);
433 
434     hr = IXMLDOMAttribute_get_ownerDocument(iface, &doc);
435     if (hr == S_OK)
436     {
437         IXMLDOMDocument3 *doc3;
438 
439         hr = IXMLDOMDocument_QueryInterface(doc, &IID_IXMLDOMDocument3, (void**)&doc3);
440         IXMLDOMDocument_Release(doc);
441 
442         if (hr == S_OK)
443         {
444             VARIANT schemas;
445 
446             hr = IXMLDOMDocument3_get_schemas(doc3, &schemas);
447             IXMLDOMDocument3_Release(doc3);
448 
449             if (hr != S_OK)
450                 return IXMLDOMAttribute_get_value(iface, value);
451             else
452             {
453                 FIXME("need to query schema for attribute type\n");
454                 VariantClear(&schemas);
455             }
456         }
457     }
458 
459     return return_null_var(value);
460 }
461 
462 static HRESULT WINAPI domattr_put_nodeTypedValue(
463     IXMLDOMAttribute *iface,
464     VARIANT typedValue)
465 {
466     domattr *This = impl_from_IXMLDOMAttribute( iface );
467     FIXME("(%p)->(%s)\n", This, debugstr_variant(&typedValue));
468     return E_NOTIMPL;
469 }
470 
471 static HRESULT WINAPI domattr_get_dataType(
472     IXMLDOMAttribute *iface,
473     VARIANT* typename)
474 {
475     domattr *This = impl_from_IXMLDOMAttribute( iface );
476     TRACE("(%p)->(%p)\n", This, typename);
477     return return_null_var( typename );
478 }
479 
480 static HRESULT WINAPI domattr_put_dataType(
481     IXMLDOMAttribute *iface,
482     BSTR p)
483 {
484     domattr *This = impl_from_IXMLDOMAttribute( iface );
485 
486     FIXME("(%p)->(%s)\n", This, debugstr_w(p));
487 
488     if(!p)
489         return E_INVALIDARG;
490 
491     return E_FAIL;
492 }
493 
494 static HRESULT WINAPI domattr_get_xml(
495     IXMLDOMAttribute *iface,
496     BSTR* p)
497 {
498     domattr *This = impl_from_IXMLDOMAttribute( iface );
499 
500     TRACE("(%p)->(%p)\n", This, p);
501 
502     return node_get_xml(&This->node, FALSE, p);
503 }
504 
505 static HRESULT WINAPI domattr_transformNode(
506     IXMLDOMAttribute *iface,
507     IXMLDOMNode *node, BSTR *p)
508 {
509     domattr *This = impl_from_IXMLDOMAttribute( iface );
510     TRACE("(%p)->(%p %p)\n", This, node, p);
511     return node_transform_node(&This->node, node, p);
512 }
513 
514 static HRESULT WINAPI domattr_selectNodes(
515     IXMLDOMAttribute *iface,
516     BSTR p, IXMLDOMNodeList** outList)
517 {
518     domattr *This = impl_from_IXMLDOMAttribute( iface );
519     TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outList);
520     return node_select_nodes(&This->node, p, outList);
521 }
522 
523 static HRESULT WINAPI domattr_selectSingleNode(
524     IXMLDOMAttribute *iface,
525     BSTR p, IXMLDOMNode** outNode)
526 {
527     domattr *This = impl_from_IXMLDOMAttribute( iface );
528     TRACE("(%p)->(%s %p)\n", This, debugstr_w(p), outNode);
529     return node_select_singlenode(&This->node, p, outNode);
530 }
531 
532 static HRESULT WINAPI domattr_get_parsed(
533     IXMLDOMAttribute *iface,
534     VARIANT_BOOL* isParsed)
535 {
536     domattr *This = impl_from_IXMLDOMAttribute( iface );
537     FIXME("(%p)->(%p) stub!\n", This, isParsed);
538     *isParsed = VARIANT_TRUE;
539     return S_OK;
540 }
541 
542 static HRESULT WINAPI domattr_get_namespaceURI(
543     IXMLDOMAttribute *iface,
544     BSTR* p)
545 {
546     domattr *This = impl_from_IXMLDOMAttribute( iface );
547     xmlNsPtr ns = This->node.node->ns;
548 
549     TRACE("(%p)->(%p)\n", This, p);
550 
551     if (!p)
552         return E_INVALIDARG;
553 
554     *p = NULL;
555 
556     if (ns)
557     {
558         /* special case for default namespace definition */
559         if (xmlStrEqual(This->node.node->name, xmlns))
560             *p = bstr_from_xmlChar(xmlns);
561         else if (xmlStrEqual(ns->prefix, xmlns))
562             *p = SysAllocStringLen(NULL, 0);
563         else if (ns->href)
564             *p = bstr_from_xmlChar(ns->href);
565     }
566 
567     TRACE("uri: %s\n", debugstr_w(*p));
568 
569     return *p ? S_OK : S_FALSE;
570 }
571 
572 static HRESULT WINAPI domattr_get_prefix(
573     IXMLDOMAttribute *iface,
574     BSTR* prefix)
575 {
576     domattr *This = impl_from_IXMLDOMAttribute( iface );
577     xmlNsPtr ns = This->node.node->ns;
578 
579     TRACE("(%p)->(%p)\n", This, prefix);
580 
581     if (!prefix) return E_INVALIDARG;
582 
583     *prefix = NULL;
584 
585     if (ns)
586     {
587         /* special case for default namespace definition */
588         if (xmlStrEqual(This->node.node->name, xmlns))
589             *prefix = bstr_from_xmlChar(xmlns);
590         else if (ns->prefix)
591             *prefix = bstr_from_xmlChar(ns->prefix);
592     }
593 
594     TRACE("prefix: %s\n", debugstr_w(*prefix));
595 
596     return *prefix ? S_OK : S_FALSE;
597 }
598 
599 static HRESULT WINAPI domattr_get_baseName(
600     IXMLDOMAttribute *iface,
601     BSTR* name)
602 {
603     domattr *This = impl_from_IXMLDOMAttribute( iface );
604     TRACE("(%p)->(%p)\n", This, name);
605     return node_get_base_name( &This->node, name );
606 }
607 
608 static HRESULT WINAPI domattr_transformNodeToObject(
609     IXMLDOMAttribute *iface,
610     IXMLDOMNode* domNode, VARIANT var1)
611 {
612     domattr *This = impl_from_IXMLDOMAttribute( iface );
613     FIXME("(%p)->(%p %s)\n", This, domNode, debugstr_variant(&var1));
614     return E_NOTIMPL;
615 }
616 
617 static HRESULT WINAPI domattr_get_name(
618     IXMLDOMAttribute *iface,
619     BSTR *p)
620 {
621     domattr *This = impl_from_IXMLDOMAttribute( iface );
622 
623     TRACE("(%p)->(%p)\n", This, p);
624 
625     return node_get_nodeName(&This->node, p);
626 }
627 
628 static HRESULT WINAPI domattr_get_value(
629     IXMLDOMAttribute *iface,
630     VARIANT *value)
631 {
632     domattr *This = impl_from_IXMLDOMAttribute( iface );
633 
634     TRACE("(%p)->(%p)\n", This, value);
635 
636     return node_get_content(&This->node, value);
637 }
638 
639 static HRESULT WINAPI domattr_put_value(
640     IXMLDOMAttribute *iface,
641     VARIANT value)
642 {
643     domattr *This = impl_from_IXMLDOMAttribute( iface );
644 
645     TRACE("(%p)->(%s)\n", This, debugstr_variant(&value));
646 
647     return node_put_value_escaped(&This->node, &value);
648 }
649 
650 static const struct IXMLDOMAttributeVtbl domattr_vtbl =
651 {
652     domattr_QueryInterface,
653     domattr_AddRef,
654     domattr_Release,
655     domattr_GetTypeInfoCount,
656     domattr_GetTypeInfo,
657     domattr_GetIDsOfNames,
658     domattr_Invoke,
659     domattr_get_nodeName,
660     domattr_get_nodeValue,
661     domattr_put_nodeValue,
662     domattr_get_nodeType,
663     domattr_get_parentNode,
664     domattr_get_childNodes,
665     domattr_get_firstChild,
666     domattr_get_lastChild,
667     domattr_get_previousSibling,
668     domattr_get_nextSibling,
669     domattr_get_attributes,
670     domattr_insertBefore,
671     domattr_replaceChild,
672     domattr_removeChild,
673     domattr_appendChild,
674     domattr_hasChildNodes,
675     domattr_get_ownerDocument,
676     domattr_cloneNode,
677     domattr_get_nodeTypeString,
678     domattr_get_text,
679     domattr_put_text,
680     domattr_get_specified,
681     domattr_get_definition,
682     domattr_get_nodeTypedValue,
683     domattr_put_nodeTypedValue,
684     domattr_get_dataType,
685     domattr_put_dataType,
686     domattr_get_xml,
687     domattr_transformNode,
688     domattr_selectNodes,
689     domattr_selectSingleNode,
690     domattr_get_parsed,
691     domattr_get_namespaceURI,
692     domattr_get_prefix,
693     domattr_get_baseName,
694     domattr_transformNodeToObject,
695     domattr_get_name,
696     domattr_get_value,
697     domattr_put_value
698 };
699 
700 static const tid_t domattr_iface_tids[] = {
701     IXMLDOMAttribute_tid,
702     0
703 };
704 
705 static dispex_static_data_t domattr_dispex = {
706     NULL,
707     IXMLDOMAttribute_tid,
708     NULL,
709     domattr_iface_tids
710 };
711 
712 IUnknown* create_attribute( xmlNodePtr attribute )
713 {
714     domattr *This;
715 
716     This = heap_alloc( sizeof *This );
717     if ( !This )
718         return NULL;
719 
720     This->IXMLDOMAttribute_iface.lpVtbl = &domattr_vtbl;
721     This->ref = 1;
722 
723     init_xmlnode(&This->node, attribute, (IXMLDOMNode*)&This->IXMLDOMAttribute_iface, &domattr_dispex);
724 
725     return (IUnknown*)&This->IXMLDOMAttribute_iface;
726 }
727 
728 #endif
729