2 * XML Element implementation
4 * Copyright 2007 James Hawkins
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.
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.
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
27 # include <libxml/parser.h>
28 # include <libxml/xmlerror.h>
38 #include "wine/debug.h"
40 #include "msxml_private.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
46 static HRESULT XMLElementCollection_create( IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj );
48 /**********************************************************************
51 typedef struct _xmlelem
53 IXMLElement IXMLElement_iface;
59 static inline xmlelem *impl_from_IXMLElement(IXMLElement *iface)
61 return CONTAINING_RECORD(iface, xmlelem, IXMLElement_iface);
64 static HRESULT WINAPI xmlelem_QueryInterface(IXMLElement *iface, REFIID riid, void** ppvObject)
66 xmlelem *This = impl_from_IXMLElement(iface);
68 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
70 if (IsEqualGUID(riid, &IID_IUnknown) ||
71 IsEqualGUID(riid, &IID_IDispatch) ||
72 IsEqualGUID(riid, &IID_IXMLElement))
78 FIXME("interface %s not implemented\n", debugstr_guid(riid));
83 IXMLElement_AddRef(iface);
88 static ULONG WINAPI xmlelem_AddRef(IXMLElement *iface)
90 xmlelem *This = impl_from_IXMLElement(iface);
92 return InterlockedIncrement(&This->ref);
95 static ULONG WINAPI xmlelem_Release(IXMLElement *iface)
97 xmlelem *This = impl_from_IXMLElement(iface);
102 ref = InterlockedDecrement(&This->ref);
105 if (This->own) xmlFreeNode(This->node);
112 static HRESULT WINAPI xmlelem_GetTypeInfoCount(IXMLElement *iface, UINT* pctinfo)
114 xmlelem *This = impl_from_IXMLElement(iface);
116 TRACE("(%p)->(%p)\n", This, pctinfo);
123 static HRESULT WINAPI xmlelem_GetTypeInfo(IXMLElement *iface, UINT iTInfo,
124 LCID lcid, ITypeInfo** ti)
126 xmlelem *This = impl_from_IXMLElement(iface);
129 TRACE("(%p)->(%u %u %p)\n", This, iTInfo, lcid, ti);
131 hr = get_typeinfo(IXMLElement_tid, ti);
132 ITypeInfo_AddRef(*ti);
136 static HRESULT WINAPI xmlelem_GetIDsOfNames(IXMLElement *iface, REFIID riid,
137 LPOLESTR* rgszNames, UINT cNames,
138 LCID lcid, DISPID* rgDispId)
140 xmlelem *This = impl_from_IXMLElement(iface);
144 TRACE("(%p)->(%s %p %u %u %p)\n", This, debugstr_guid(riid), rgszNames, cNames,
147 if(!rgszNames || cNames == 0 || !rgDispId)
150 hr = get_typeinfo(IXMLElement_tid, &typeinfo);
152 hr = ITypeInfo_GetIDsOfNames(typeinfo, rgszNames, cNames, rgDispId);
157 static HRESULT WINAPI xmlelem_Invoke(IXMLElement *iface, DISPID dispIdMember,
158 REFIID riid, LCID lcid, WORD wFlags,
159 DISPPARAMS* pDispParams, VARIANT* pVarResult,
160 EXCEPINFO* pExcepInfo, UINT* puArgErr)
162 xmlelem *This = impl_from_IXMLElement(iface);
166 TRACE("(%p)->(%d %s %d %d %p %p %p %p)\n", This, dispIdMember, debugstr_guid(riid),
167 lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
169 hr = get_typeinfo(IXMLElement_tid, &typeinfo);
171 hr = ITypeInfo_Invoke(typeinfo, &This->IXMLElement_iface, dispIdMember, wFlags, pDispParams,
172 pVarResult, pExcepInfo, puArgErr);
177 static HRESULT WINAPI xmlelem_get_tagName(IXMLElement *iface, BSTR *p)
179 xmlelem *This = impl_from_IXMLElement(iface);
181 TRACE("(%p)->(%p)\n", This, p);
186 *p = bstr_from_xmlChar(This->node->name);
187 CharUpperBuffW(*p, SysStringLen(*p));
189 TRACE("returning %s\n", debugstr_w(*p));
194 static HRESULT WINAPI xmlelem_put_tagName(IXMLElement *iface, BSTR p)
196 xmlelem *This = impl_from_IXMLElement(iface);
198 FIXME("(%p)->(%s): stub\n", This, debugstr_w(p));
206 static HRESULT WINAPI xmlelem_get_parent(IXMLElement *iface, IXMLElement **parent)
208 xmlelem *This = impl_from_IXMLElement(iface);
210 TRACE("(%p)->(%p)\n", This, parent);
217 if (!This->node->parent)
220 return XMLElement_create((IUnknown *)iface, This->node->parent, (LPVOID *)parent, FALSE);
223 static HRESULT WINAPI xmlelem_setAttribute(IXMLElement *iface, BSTR strPropertyName,
224 VARIANT PropertyValue)
226 xmlelem *This = impl_from_IXMLElement(iface);
227 xmlChar *name, *value;
230 TRACE("(%p)->(%s %s)\n", This, debugstr_w(strPropertyName), debugstr_variant(&PropertyValue));
232 if (!strPropertyName || V_VT(&PropertyValue) != VT_BSTR)
235 name = xmlchar_from_wchar(strPropertyName);
236 value = xmlchar_from_wchar(V_BSTR(&PropertyValue));
237 attr = xmlSetProp(This->node, name, value);
241 return (attr) ? S_OK : S_FALSE;
244 static HRESULT WINAPI xmlelem_getAttribute(IXMLElement *iface, BSTR name,
247 static const WCHAR xmllangW[] = { 'x','m','l',':','l','a','n','g',0 };
248 xmlelem *This = impl_from_IXMLElement(iface);
251 TRACE("(%p)->(%s, %p)\n", This, debugstr_w(name), value);
257 V_BSTR(value) = NULL;
262 /* case for xml:lang attribute */
263 if (!lstrcmpiW(name, xmllangW))
266 ns = xmlSearchNs(This->node->doc, This->node, (xmlChar*)"xml");
267 val = xmlGetNsProp(This->node, (xmlChar*)"lang", ns->href);
274 xml_name = xmlchar_from_wchar(name);
275 attr = This->node->properties;
280 attr_name = bstr_from_xmlChar(attr->name);
281 if (!lstrcmpiW(name, attr_name))
283 val = xmlNodeListGetString(attr->doc, attr->children, 1);
284 SysFreeString(attr_name);
289 SysFreeString(attr_name);
297 V_VT(value) = VT_BSTR;
298 V_BSTR(value) = bstr_from_xmlChar(val);
302 TRACE("returning %s\n", debugstr_w(V_BSTR(value)));
303 return (val) ? S_OK : S_FALSE;
306 static HRESULT WINAPI xmlelem_removeAttribute(IXMLElement *iface, BSTR strPropertyName)
308 xmlelem *This = impl_from_IXMLElement(iface);
312 HRESULT hr = S_FALSE;
314 TRACE("(%p)->(%s)\n", This, debugstr_w(strPropertyName));
316 if (!strPropertyName)
319 name = xmlchar_from_wchar(strPropertyName);
320 attr = xmlHasProp(This->node, name);
324 res = xmlRemoveProp(attr);
334 static HRESULT WINAPI xmlelem_get_children(IXMLElement *iface, IXMLElementCollection **p)
336 xmlelem *This = impl_from_IXMLElement(iface);
338 TRACE("(%p)->(%p)\n", This, p);
343 return XMLElementCollection_create((IUnknown *)iface, This->node, (LPVOID *)p);
346 static LONG type_libxml_to_msxml(xmlElementType type)
350 case XML_ELEMENT_NODE:
351 return XMLELEMTYPE_ELEMENT;
353 return XMLELEMTYPE_TEXT;
354 case XML_COMMENT_NODE:
355 return XMLELEMTYPE_COMMENT;
356 case XML_DOCUMENT_NODE:
357 return XMLELEMTYPE_DOCUMENT;
359 return XMLELEMTYPE_DTD;
361 return XMLELEMTYPE_PI;
366 return XMLELEMTYPE_OTHER;
369 static HRESULT WINAPI xmlelem_get_type(IXMLElement *iface, LONG *p)
371 xmlelem *This = impl_from_IXMLElement(iface);
373 TRACE("(%p)->(%p)\n", This, p);
378 *p = type_libxml_to_msxml(This->node->type);
379 TRACE("returning %d\n", *p);
383 static HRESULT WINAPI xmlelem_get_text(IXMLElement *iface, BSTR *p)
385 xmlelem *This = impl_from_IXMLElement(iface);
388 TRACE("(%p)->(%p)\n", This, p);
393 content = xmlNodeGetContent(This->node);
394 *p = bstr_from_xmlChar(content);
395 TRACE("returning %s\n", debugstr_w(*p));
401 static HRESULT WINAPI xmlelem_put_text(IXMLElement *iface, BSTR p)
403 xmlelem *This = impl_from_IXMLElement(iface);
406 TRACE("(%p)->(%s)\n", This, debugstr_w(p));
408 /* FIXME: test which types can be used */
409 if (This->node->type == XML_ELEMENT_NODE)
412 content = xmlchar_from_wchar(p);
413 xmlNodeSetContent(This->node, content);
420 static HRESULT WINAPI xmlelem_addChild(IXMLElement *iface, IXMLElement *pChildElem,
421 LONG lIndex, LONG lreserved)
423 xmlelem *This = impl_from_IXMLElement(iface);
424 xmlelem *childElem = impl_from_IXMLElement(pChildElem);
427 TRACE("(%p)->(%p %d %d)\n", This, pChildElem, lIndex, lreserved);
430 child = xmlAddChild(This->node, childElem->node);
432 child = xmlAddNextSibling(This->node, childElem->node->last);
434 /* parent is responsible for child data */
435 if (child) childElem->own = FALSE;
437 return (child) ? S_OK : S_FALSE;
440 static HRESULT WINAPI xmlelem_removeChild(IXMLElement *iface, IXMLElement *pChildElem)
442 xmlelem *This = impl_from_IXMLElement(iface);
443 xmlelem *childElem = impl_from_IXMLElement(pChildElem);
445 TRACE("(%p)->(%p)\n", This, childElem);
450 /* only supported for This is childElem parent case */
451 if (This->node != childElem->node->parent)
454 xmlUnlinkNode(childElem->node);
455 /* standalone element now */
456 childElem->own = TRUE;
461 static const struct IXMLElementVtbl xmlelem_vtbl =
463 xmlelem_QueryInterface,
466 xmlelem_GetTypeInfoCount,
468 xmlelem_GetIDsOfNames,
473 xmlelem_setAttribute,
474 xmlelem_getAttribute,
475 xmlelem_removeAttribute,
476 xmlelem_get_children,
484 HRESULT XMLElement_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj, BOOL own)
488 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
495 elem = heap_alloc(sizeof (*elem));
497 return E_OUTOFMEMORY;
499 elem->IXMLElement_iface.lpVtbl = &xmlelem_vtbl;
504 *ppObj = &elem->IXMLElement_iface;
506 TRACE("returning iface %p\n", *ppObj);
510 /************************************************************************
511 * IXMLElementCollection
513 typedef struct _xmlelem_collection
515 IXMLElementCollection IXMLElementCollection_iface;
516 IEnumVARIANT IEnumVARIANT_iface;
521 /* IEnumVARIANT members */
523 } xmlelem_collection;
525 static inline LONG xmlelem_collection_updatelength(xmlelem_collection *collection)
527 xmlNodePtr ptr = collection->node->children;
529 collection->length = 0;
532 collection->length++;
535 return collection->length;
538 static inline xmlelem_collection *impl_from_IXMLElementCollection(IXMLElementCollection *iface)
540 return CONTAINING_RECORD(iface, xmlelem_collection, IXMLElementCollection_iface);
543 static inline xmlelem_collection *impl_from_IEnumVARIANT(IEnumVARIANT *iface)
545 return CONTAINING_RECORD(iface, xmlelem_collection, IEnumVARIANT_iface);
548 static HRESULT WINAPI xmlelem_collection_QueryInterface(IXMLElementCollection *iface, REFIID riid, void** ppvObject)
550 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
552 TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppvObject);
554 if (IsEqualGUID(riid, &IID_IUnknown) ||
555 IsEqualGUID(riid, &IID_IXMLElementCollection))
559 else if (IsEqualGUID(riid, &IID_IEnumVARIANT))
561 *ppvObject = &This->IEnumVARIANT_iface;
565 FIXME("interface %s not implemented\n", debugstr_guid(riid));
566 return E_NOINTERFACE;
569 IXMLElementCollection_AddRef(iface);
574 static ULONG WINAPI xmlelem_collection_AddRef(IXMLElementCollection *iface)
576 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
577 TRACE("(%p)\n", This);
578 return InterlockedIncrement(&This->ref);
581 static ULONG WINAPI xmlelem_collection_Release(IXMLElementCollection *iface)
583 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
586 TRACE("(%p)\n", This);
588 ref = InterlockedDecrement(&This->ref);
597 static HRESULT WINAPI xmlelem_collection_GetTypeInfoCount(IXMLElementCollection *iface, UINT* pctinfo)
603 static HRESULT WINAPI xmlelem_collection_GetTypeInfo(IXMLElementCollection *iface, UINT iTInfo,
604 LCID lcid, ITypeInfo** ppTInfo)
610 static HRESULT WINAPI xmlelem_collection_GetIDsOfNames(IXMLElementCollection *iface, REFIID riid,
611 LPOLESTR* rgszNames, UINT cNames,
612 LCID lcid, DISPID* rgDispId)
618 static HRESULT WINAPI xmlelem_collection_Invoke(IXMLElementCollection *iface, DISPID dispIdMember,
619 REFIID riid, LCID lcid, WORD wFlags,
620 DISPPARAMS* pDispParams, VARIANT* pVarResult,
621 EXCEPINFO* pExcepInfo, UINT* puArgErr)
627 static HRESULT WINAPI xmlelem_collection_put_length(IXMLElementCollection *iface, LONG v)
629 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
630 TRACE("(%p)->(%d)\n", This, v);
634 static HRESULT WINAPI xmlelem_collection_get_length(IXMLElementCollection *iface, LONG *p)
636 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
638 TRACE("(%p)->(%p)\n", This, p);
643 *p = xmlelem_collection_updatelength(This);
647 static HRESULT WINAPI xmlelem_collection_get__newEnum(IXMLElementCollection *iface, IUnknown **ppUnk)
649 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
651 TRACE("(%p)->(%p)\n", This, ppUnk);
656 *ppUnk = (IUnknown *)This;
657 IUnknown_AddRef(*ppUnk);
661 static HRESULT WINAPI xmlelem_collection_item(IXMLElementCollection *iface, VARIANT var1,
662 VARIANT var2, IDispatch **ppDisp)
664 xmlelem_collection *This = impl_from_IXMLElementCollection(iface);
665 xmlNodePtr ptr = This->node->children;
668 TRACE("(%p)->(%s %s %p)\n", This, debugstr_variant(&var1), debugstr_variant(&var2), ppDisp);
679 xmlelem_collection_updatelength(This);
680 if (index >= This->length)
683 for (i = 0; i < index; i++)
686 return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)ppDisp, FALSE);
689 static const struct IXMLElementCollectionVtbl xmlelem_collection_vtbl =
691 xmlelem_collection_QueryInterface,
692 xmlelem_collection_AddRef,
693 xmlelem_collection_Release,
694 xmlelem_collection_GetTypeInfoCount,
695 xmlelem_collection_GetTypeInfo,
696 xmlelem_collection_GetIDsOfNames,
697 xmlelem_collection_Invoke,
698 xmlelem_collection_put_length,
699 xmlelem_collection_get_length,
700 xmlelem_collection_get__newEnum,
701 xmlelem_collection_item
704 /************************************************************************
705 * xmlelem_collection implementation of IEnumVARIANT.
707 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_QueryInterface(
708 IEnumVARIANT *iface, REFIID riid, LPVOID *ppvObj)
710 xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
711 return IXMLDocument_QueryInterface((IXMLDocument *)this, riid, ppvObj);
714 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_AddRef(
717 xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
718 return IXMLDocument_AddRef((IXMLDocument *)this);
721 static ULONG WINAPI xmlelem_collection_IEnumVARIANT_Release(
724 xmlelem_collection *this = impl_from_IEnumVARIANT(iface);
725 return IXMLDocument_Release((IXMLDocument *)this);
728 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Next(
729 IEnumVARIANT *iface, ULONG celt, VARIANT *rgVar, ULONG *fetched)
731 xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
732 xmlNodePtr ptr = This->current;
734 TRACE("(%p)->(%d %p %p)\n", This, celt, rgVar, fetched);
739 /* FIXME: handle celt */
744 This->current = This->current->next;
747 V_VT(rgVar) = VT_EMPTY;
748 if (fetched) *fetched = 0;
752 V_VT(rgVar) = VT_DISPATCH;
753 return XMLElement_create((IUnknown *)iface, ptr, (LPVOID *)&V_DISPATCH(rgVar), FALSE);
756 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Skip(
757 IEnumVARIANT *iface, ULONG celt)
759 xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
760 FIXME("(%p)->(%d): stub\n", This, celt);
764 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Reset(
767 xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
768 TRACE("(%p)\n", This);
769 This->current = This->node->children;
773 static HRESULT WINAPI xmlelem_collection_IEnumVARIANT_Clone(
774 IEnumVARIANT *iface, IEnumVARIANT **ppEnum)
776 xmlelem_collection *This = impl_from_IEnumVARIANT(iface);
777 FIXME("(%p)->(%p): stub\n", This, ppEnum);
781 static const struct IEnumVARIANTVtbl xmlelem_collection_IEnumVARIANTvtbl =
783 xmlelem_collection_IEnumVARIANT_QueryInterface,
784 xmlelem_collection_IEnumVARIANT_AddRef,
785 xmlelem_collection_IEnumVARIANT_Release,
786 xmlelem_collection_IEnumVARIANT_Next,
787 xmlelem_collection_IEnumVARIANT_Skip,
788 xmlelem_collection_IEnumVARIANT_Reset,
789 xmlelem_collection_IEnumVARIANT_Clone
792 static HRESULT XMLElementCollection_create(IUnknown *pUnkOuter, xmlNodePtr node, LPVOID *ppObj)
794 xmlelem_collection *collection;
796 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
803 collection = heap_alloc(sizeof (*collection));
805 return E_OUTOFMEMORY;
807 collection->IXMLElementCollection_iface.lpVtbl = &xmlelem_collection_vtbl;
808 collection->IEnumVARIANT_iface.lpVtbl = &xmlelem_collection_IEnumVARIANTvtbl;
810 collection->length = 0;
811 collection->node = node;
812 collection->current = node->children;
813 xmlelem_collection_updatelength(collection);
815 *ppObj = &collection->IXMLElementCollection_iface;
817 TRACE("returning iface %p\n", *ppObj);