[PATCH] msxml3: Implement mxwriter ISAXContentHandler domdoc destination.
Jefferson Carpenter
jefferson at aoeu2code.com
Wed Jan 20 22:48:05 CST 2021
Here's an implementation of DOMDocument output for mxwriter. It only
implements the ISAXContentHandler mxwriter interface.
Supersedes 198351.
thanks,
Jefferson
-------------- next part --------------
From 07fd479930b6ea8d8dceddd9dd1924a99601a1f6 Mon Sep 17 00:00:00 2001
From: Jefferson Carpenter <jeffersoncarpenter2 at gmail.com>
Date: Wed, 20 Jan 2021 01:07:44 +0000
Subject: [PATCH] msxml3: Implement mxwriter ISAXContentHandler domdoc
destination.
Signed-off-by: Jefferson Carpenter <jeffersoncarpenter2 at gmail.com>
---
dlls/msxml3/mxwriter.c | 406 +++++++++++++++++++++++++++-------
dlls/msxml3/tests/saxreader.c | 217 ++++++++++++++++++
2 files changed, 547 insertions(+), 76 deletions(-)
diff --git a/dlls/msxml3/mxwriter.c b/dlls/msxml3/mxwriter.c
index 029e9aac0d0..0b8eddc44cd 100644
--- a/dlls/msxml3/mxwriter.c
+++ b/dlls/msxml3/mxwriter.c
@@ -142,6 +142,13 @@ typedef enum
EscapeText
} escape_mode;
+typedef enum
+{
+ OutputIStream,
+ OutputString,
+ OutputDOMDocument,
+} output_type;
+
typedef struct
{
struct list entry;
@@ -193,7 +200,11 @@ typedef struct
we don't have to close */
BSTR element;
+ IXMLDOMNode *cur_node; /* current node for DOMDocument destination */
+
+ output_type output_ty;
IStream *dest;
+ IXMLDOMDocument *dest_doc;
output_buffer buffer;
} mxwriter;
@@ -715,6 +726,32 @@ static HRESULT writer_get_property(const mxwriter *writer, mxwriter_prop propert
return S_OK;
}
+static void push_cur_node(mxwriter *writer, IXMLDOMNode *node)
+{
+ if (writer->cur_node) {
+ IXMLDOMNode_Release(writer->cur_node);
+ }
+
+ IXMLDOMNode_AddRef(node);
+ writer->cur_node = node;
+}
+
+static HRESULT pop_cur_node(mxwriter *writer)
+{
+ HRESULT hr;
+ IXMLDOMNode *parent_node = NULL;
+
+ if (!writer->cur_node) return E_INVALIDARG;
+
+ hr = IXMLDOMNode_get_parentNode(writer->cur_node, &parent_node);
+ if (FAILED(hr)) return hr;
+
+ IXMLDOMNode_Release(writer->cur_node);
+ writer->cur_node = parent_node;
+
+ return S_OK;
+}
+
static inline mxwriter *impl_from_IMXWriter(IMXWriter *iface)
{
return CONTAINING_RECORD(iface, mxwriter, IMXWriter_iface);
@@ -863,6 +900,9 @@ static ULONG WINAPI mxwriter_Release(IMXWriter *iface)
free_output_buffer(&This->buffer);
if (This->dest) IStream_Release(This->dest);
+ while (!FAILED(pop_cur_node(This)));
+ if (This->dest_doc) IXMLDOMDocument_Release(This->dest_doc);
+
SysFreeString(This->version);
SysFreeString(This->encoding);
@@ -926,8 +966,14 @@ static HRESULT WINAPI mxwriter_put_output(IMXWriter *iface, VARIANT dest)
case VT_EMPTY:
{
if (This->dest) IStream_Release(This->dest);
+ while (!FAILED(pop_cur_node(This)));
+ if (This->dest_doc) IXMLDOMDocument_Release(This->dest_doc);
+
This->dest = NULL;
+ This->dest_doc = NULL;
+
reset_output_buffer(This);
+ This->output_ty = OutputString;
break;
}
case VT_UNKNOWN:
@@ -941,13 +987,41 @@ static HRESULT WINAPI mxwriter_put_output(IMXWriter *iface, VARIANT dest)
reset_output_buffer(This);
if (This->dest) IStream_Release(This->dest);
+ while (!FAILED(pop_cur_node(This)));
+ if (This->dest_doc) IXMLDOMDocument_Release(This->dest_doc);
+
This->dest = stream;
+ This->dest_doc = NULL;
+ This->output_ty = OutputIStream;
break;
}
FIXME("unhandled interface type for VT_UNKNOWN destination\n");
return E_NOTIMPL;
}
+ case VT_DISPATCH:
+ {
+ IXMLDOMDocument *document;
+
+ hr = IDispatch_QueryInterface(V_DISPATCH(&dest), &IID_IXMLDOMDocument, (void**)&document);
+ if (hr == S_OK) {
+ /* Reset output buffer to initial state. */
+ reset_output_buffer(This);
+
+ if (This->dest) IStream_Release(This->dest);
+ while (!FAILED(pop_cur_node(This)));
+ if (This->dest_doc) IXMLDOMDocument_Release(This->dest_doc);
+
+ This->dest = NULL;
+ This->dest_doc = document;
+ push_cur_node(This, (IXMLDOMNode*)document);
+ This->output_ty = OutputDOMDocument;
+ break;
+ }
+
+ FIXME("unhandled interface type for VT_DISPATCH destination\n");
+ return E_NOTIMPL;
+ }
default:
FIXME("unhandled destination type %s\n", debugstr_variant(&dest));
return E_NOTIMPL;
@@ -1223,28 +1297,36 @@ static HRESULT WINAPI SAXContentHandler_startDocument(ISAXContentHandler *iface)
TRACE("(%p)\n", This);
- /* If properties have been changed since the last "endDocument" call
- * we need to reset the output buffer. If we don't the output buffer
- * could end up with multiple XML documents in it, plus this seems to
- * be how Windows works.
- */
- if (This->prop_changed) {
- reset_output_buffer(This);
- This->prop_changed = FALSE;
- }
+ switch (This->output_ty)
+ {
+ case OutputIStream:
+ case OutputString:
+ /* If properties have been changed since the last "endDocument" call
+ * we need to reset the output buffer. If we don't the output buffer
+ * could end up with multiple XML documents in it, plus this seems to
+ * be how Windows works.
+ */
+ if (This->prop_changed) {
+ reset_output_buffer(This);
+ This->prop_changed = FALSE;
+ }
- if (This->props[MXWriter_OmitXmlDecl] == VARIANT_TRUE) return S_OK;
+ if (This->props[MXWriter_OmitXmlDecl] == VARIANT_TRUE) return S_OK;
- write_prolog_buffer(This);
+ write_prolog_buffer(This);
- if (This->dest && This->xml_enc == XmlEncoding_UTF16) {
- static const char utf16BOM[] = {0xff,0xfe};
+ if (This->dest && This->xml_enc == XmlEncoding_UTF16) {
+ static const char utf16BOM[] = {0xff,0xfe};
- if (This->props[MXWriter_BOM] == VARIANT_TRUE)
- /* Windows passes a NULL pointer as the pcbWritten parameter and
- * ignores any error codes returned from this Write call.
- */
- IStream_Write(This->dest, utf16BOM, sizeof(utf16BOM), NULL);
+ if (This->props[MXWriter_BOM] == VARIANT_TRUE)
+ /* Windows passes a NULL pointer as the pcbWritten parameter and
+ * ignores any error codes returned from this Write call.
+ */
+ IStream_Write(This->dest, utf16BOM, sizeof(utf16BOM), NULL);
+ }
+ break;
+ case OutputDOMDocument:
+ break;
}
return S_OK;
@@ -1254,7 +1336,15 @@ static HRESULT WINAPI SAXContentHandler_endDocument(ISAXContentHandler *iface)
{
mxwriter *This = impl_from_ISAXContentHandler( iface );
TRACE("(%p)\n", This);
- This->prop_changed = FALSE;
+ switch (This->output_ty)
+ {
+ case OutputIStream:
+ case OutputString:
+ This->prop_changed = FALSE;
+ break;
+ case OutputDOMDocument:
+ break;
+ }
return flush_output_buffer(This);
}
@@ -1333,32 +1423,96 @@ static HRESULT WINAPI SAXContentHandler_startElement(
(nQName == -1 && This->class_version == MSXML6))
return E_INVALIDARG;
- mxwriter_write_starttag(This, QName, nQName);
+ switch (This->output_ty) {
+ case OutputIStream:
+ case OutputString:
+ mxwriter_write_starttag(This, QName, nQName);
- if (attr)
- {
- int length, i, escape;
- HRESULT hr;
+ if (attr)
+ {
+ int length, i, escape;
+ HRESULT hr;
- hr = ISAXAttributes_getLength(attr, &length);
- if (FAILED(hr)) return hr;
+ hr = ISAXAttributes_getLength(attr, &length);
+ if (FAILED(hr)) return hr;
- escape = This->props[MXWriter_DisableEscaping] == VARIANT_FALSE ||
+ escape = This->props[MXWriter_DisableEscaping] == VARIANT_FALSE ||
(This->class_version == MSXML4 || This->class_version == MSXML6);
- for (i = 0; i < length; i++)
- {
- int qname_len = 0, value_len = 0;
- const WCHAR *qname, *value;
+ for (i = 0; i < length; i++)
+ {
+ int qname_len = 0, value_len = 0;
+ const WCHAR *qname, *value;
- hr = ISAXAttributes_getQName(attr, i, &qname, &qname_len);
- if (FAILED(hr)) return hr;
+ hr = ISAXAttributes_getQName(attr, i, &qname, &qname_len);
+ if (FAILED(hr)) return hr;
+
+ hr = ISAXAttributes_getValue(attr, i, &value, &value_len);
+ if (FAILED(hr)) return hr;
- hr = ISAXAttributes_getValue(attr, i, &value, &value_len);
+ mxwriter_write_attribute(This, qname, qname_len, value, value_len, escape);
+ }
+ }
+ break;
+ case OutputDOMDocument:
+ {
+ HRESULT hr = S_OK;
+ IXMLDOMElement *element = NULL;
+ BSTR tag_name = NULL;
+
+ tag_name = SysAllocStringLen(QName, nQName);
+ if (!tag_name) {
+ hr = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ hr = IXMLDOMDocument_createElement(This->dest_doc, tag_name, &element);
+ if (FAILED(hr)) goto done;
+
+ if (attr) {
+ int length, i;
+ BSTR attribute_name = NULL;
+ VARIANT attribute_value;
+
+ hr = ISAXAttributes_getLength(attr, &length);
if (FAILED(hr)) return hr;
- mxwriter_write_attribute(This, qname, qname_len, value, value_len, escape);
+ for (i = 0; i < length; i++)
+ {
+ int qname_len = 0, value_len = 0;
+ const WCHAR *qname, *value;
+
+ hr = ISAXAttributes_getQName(attr, i, &qname, &qname_len);
+ if (FAILED(hr)) return hr;
+
+ hr = ISAXAttributes_getValue(attr, i, &value, &value_len);
+ if (FAILED(hr)) return hr;
+
+ attribute_name = SysAllocStringLen(qname, qname_len);
+ if (!attribute_name) goto done;
+
+ V_VT(&attribute_value) = VT_BSTR;
+ V_BSTR(&attribute_value) = SysAllocStringLen(value, value_len);
+ if (!V_BSTR(&attribute_value)) goto done;
+
+ IXMLDOMElement_setAttribute(element, attribute_name, attribute_value);
+
+ SysFreeString(V_BSTR(&attribute_value));
+ SysFreeString(attribute_name);
+ }
}
+
+ hr = IXMLDOMNode_appendChild(This->cur_node, (IXMLDOMNode*)element, NULL);
+ if (FAILED(hr)) goto done;
+
+ push_cur_node(This, (IXMLDOMNode*)element);
+
+ done:
+ if (element) IXMLDOMElement_Release(element);
+ if (tag_name) SysFreeString(tag_name);
+
+ return hr;
+ }
}
return S_OK;
@@ -1382,25 +1536,34 @@ static HRESULT WINAPI SAXContentHandler_endElement(
(nQName == -1 && This->class_version == MSXML6))
return E_INVALIDARG;
- writer_dec_indent(This);
-
- if (This->element)
+ switch (This->output_ty)
{
- static const WCHAR closeW[] = {'/','>'};
- write_output_buffer(This, closeW, 2);
- }
- else
- {
- static const WCHAR closetagW[] = {'<','/'};
- static const WCHAR gtW[] = {'>'};
+ case OutputIStream:
+ case OutputString:
+ writer_dec_indent(This);
- write_node_indent(This);
- write_output_buffer(This, closetagW, 2);
- write_output_buffer(This, QName, nQName);
- write_output_buffer(This, gtW, 1);
- }
+ if (This->element)
+ {
+ static const WCHAR closeW[] = {'/','>'};
+ write_output_buffer(This, closeW, 2);
+ }
+ else
+ {
+ static const WCHAR closetagW[] = {'<','/'};
+ static const WCHAR gtW[] = {'>'};
- set_element_name(This, NULL, 0);
+ write_node_indent(This);
+ write_output_buffer(This, closetagW, 2);
+ write_output_buffer(This, QName, nQName);
+ write_output_buffer(This, gtW, 1);
+ }
+
+ set_element_name(This, NULL, 0);
+ break;
+ case OutputDOMDocument:
+ pop_cur_node(This);
+ break;
+ }
return S_OK;
}
@@ -1416,25 +1579,54 @@ static HRESULT WINAPI SAXContentHandler_characters(
if (!chars) return E_INVALIDARG;
- close_element_starttag(This);
- set_element_name(This, NULL, 0);
+ switch (This->output_ty) {
+ case OutputIStream:
+ case OutputString:
+ close_element_starttag(This);
+ set_element_name(This, NULL, 0);
- if (!This->cdata)
- This->text = TRUE;
+ if (!This->cdata)
+ This->text = TRUE;
- if (nchars)
- {
- if (This->cdata || This->props[MXWriter_DisableEscaping] == VARIANT_TRUE)
- write_output_buffer(This, chars, nchars);
- else
+ if (nchars)
{
- int len = nchars;
- WCHAR *escaped;
+ if (This->cdata || This->props[MXWriter_DisableEscaping] == VARIANT_TRUE)
+ write_output_buffer(This, chars, nchars);
+ else
+ {
+ int len = nchars;
+ WCHAR *escaped;
- escaped = get_escaped_string(chars, EscapeText, &len);
- write_output_buffer(This, escaped, len);
- heap_free(escaped);
+ escaped = get_escaped_string(chars, EscapeText, &len);
+ write_output_buffer(This, escaped, len);
+ heap_free(escaped);
+ }
}
+ break;
+ case OutputDOMDocument:
+ {
+ HRESULT hr = S_OK;
+ IXMLDOMText *text_node = NULL;
+ BSTR text = NULL;
+
+ text = SysAllocStringLen(chars, nchars);
+ if (!text) {
+ hr = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ hr = IXMLDOMDocument_createTextNode(This->dest_doc, text, &text_node);
+ if (FAILED(hr)) goto done;
+
+ hr = IXMLDOMNode_appendChild(This->cur_node, (IXMLDOMNode*)text_node, NULL);
+ if (FAILED(hr)) goto done;
+
+ done:
+ if (text_node) IXMLDOMText_Release(text_node);
+ if (text) SysFreeString(text);
+
+ return hr;
+ }
}
return S_OK;
@@ -1451,7 +1643,15 @@ static HRESULT WINAPI SAXContentHandler_ignorableWhitespace(
if (!chars) return E_INVALIDARG;
- write_output_buffer(This, chars, nchars);
+ switch (This->output_ty)
+ {
+ case OutputIStream:
+ case OutputString:
+ write_output_buffer(This, chars, nchars);
+ break;
+ case OutputDOMDocument:
+ break;
+ }
return S_OK;
}
@@ -1471,20 +1671,71 @@ static HRESULT WINAPI SAXContentHandler_processingInstruction(
if (!target) return E_INVALIDARG;
- write_node_indent(This);
- write_output_buffer(This, openpiW, ARRAY_SIZE(openpiW));
+ switch (This->output_ty) {
+ case OutputIStream:
+ case OutputString:
+ write_node_indent(This);
+ write_output_buffer(This, openpiW, ARRAY_SIZE(openpiW));
- if (*target)
- write_output_buffer(This, target, ntarget);
+ if (*target)
+ write_output_buffer(This, target, ntarget);
- if (data && *data && ndata)
+ if (data && *data && ndata)
+ {
+ write_output_buffer(This, spaceW, 1);
+ write_output_buffer(This, data, ndata);
+ }
+
+ write_output_buffer(This, closepiW, ARRAY_SIZE(closepiW));
+ This->newline = TRUE;
+ break;
+ case OutputDOMDocument:
{
- write_output_buffer(This, spaceW, 1);
- write_output_buffer(This, data, ndata);
- }
+ HRESULT hr = S_OK;
+ IXMLDOMNode *first_child = NULL;
+ IXMLDOMProcessingInstruction *processing_instruction = NULL;
+ VARIANT ref_node;
+ BSTR target_bstr = NULL;
+ BSTR data_bstr = NULL;
+
+ target_bstr = SysAllocStringLen(target, ntarget);
+ if (!target_bstr) {
+ hr = E_OUTOFMEMORY;
+ goto done;
+ }
+
+ data_bstr = SysAllocStringLen(data, ndata);
+ if (!data_bstr) {
+ hr = E_OUTOFMEMORY;
+ goto done;
+ }
- write_output_buffer(This, closepiW, ARRAY_SIZE(closepiW));
- This->newline = TRUE;
+ hr = IXMLDOMDocument_createProcessingInstruction(
+ This->dest_doc, target_bstr, data_bstr, &processing_instruction
+ );
+ if (FAILED(hr)) goto done;
+
+ hr = IXMLDOMDocument_get_firstChild(This->dest_doc, &first_child);
+ if (FAILED(hr)) goto done;
+
+ V_VT(&ref_node) = VT_UNKNOWN;
+ V_UNKNOWN(&ref_node) = (IUnknown*)first_child;
+
+ hr = IXMLDOMDocument_insertBefore(
+ This->dest_doc, (IXMLDOMNode*)processing_instruction, ref_node, NULL
+ );
+ if (FAILED(hr)) goto done;
+
+ done:
+ if (first_child) IXMLDOMNode_Release(first_child);
+ if (processing_instruction)
+ IXMLDOMProcessingInstruction_Release(processing_instruction);
+ if (data_bstr) SysFreeString(data_bstr);
+ if (target_bstr) SysFreeString(target_bstr);
+
+ return hr;
+ }
+ }
return S_OK;
}
@@ -2651,7 +2902,10 @@ HRESULT MXWriter_create(MSXML_VERSION version, void **ppObj)
This->text = FALSE;
This->newline = FALSE;
+ This->output_ty = OutputString;
This->dest = NULL;
+ This->dest_doc = NULL;
+ This->cur_node = NULL;
hr = init_output_buffer(This->xml_enc, &This->buffer);
if (hr != S_OK) {
diff --git a/dlls/msxml3/tests/saxreader.c b/dlls/msxml3/tests/saxreader.c
index ab814c5f764..1a89d88ccef 100644
--- a/dlls/msxml3/tests/saxreader.c
+++ b/dlls/msxml3/tests/saxreader.c
@@ -4367,6 +4367,222 @@ static void test_mxwriter_stream(void)
free_bstrs();
}
+static void test_mxwriter_domdoc(void)
+{
+ IMXWriter *writer;
+ ISAXContentHandler *content;
+ IXMLDOMDocument3 *domdoc;
+ IDispatch *dispatch;
+ ISAXAttributes *sax_attributes;
+ IMXAttributes *mx_attributes;
+ HRESULT hr;
+ VARIANT dest;
+
+ IXMLDOMElement *root = NULL;
+ IXMLDOMNodeList *node_list = NULL;
+ IXMLDOMNode *node = NULL;
+ IXMLDOMNamedNodeMap *attribute_map = NULL;
+ IXMLDOMNode *attribute_node = NULL;
+ LONG list_length = 0;
+ BSTR str;
+
+ /* Create writer and attach DOMDocument output */
+ hr = CoCreateInstance(&CLSID_MXXMLWriter60, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IMXWriter, (void**)&writer);
+ EXPECT_HR(hr, S_OK);
+
+ hr = IMXWriter_QueryInterface(writer, &IID_ISAXContentHandler, (void**)&content);
+ EXPECT_HR(hr, S_OK);
+
+ hr = CoCreateInstance(&CLSID_DOMDocument60, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IXMLDOMDocument3, (void**)&domdoc);
+ EXPECT_HR(hr, S_OK);
+
+ hr = IXMLDOMDocument3_QueryInterface(domdoc, &IID_IDispatch, (void**)&dispatch);
+ EXPECT_HR(hr, S_OK);
+
+ V_VT(&dest) = VT_DISPATCH;
+ V_DISPATCH(&dest) = dispatch;
+
+ hr = IMXWriter_put_output(writer, dest);
+ EXPECT_HR(hr, S_OK);
+
+
+ /* Provide writer with events */
+ hr = ISAXContentHandler_startDocument(content);
+ EXPECT_HR(hr, S_OK);
+
+ hr = ISAXContentHandler_processingInstruction(
+ content,
+ L"targ", 4, L"type=\"test sheet\" test=\"something\"", 34
+ );
+ EXPECT_HR(hr, S_OK);
+
+ /* <BankAccount> */
+ hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"BankAccount", 11, NULL);
+ EXPECT_HR(hr, S_OK);
+
+ /* <Number bank="World Bank" branch="Japan">12345</Number> */
+ hr = CoCreateInstance(&CLSID_SAXAttributes60, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IMXAttributes, (void**)&mx_attributes);
+ EXPECT_HR(hr, S_OK);
+
+ hr = IMXAttributes_addAttribute(
+ mx_attributes, _bstr_("uri"), _bstr_("local"),
+ _bstr_("bank"), _bstr_("type"), _bstr_("World Bank")
+ );
+ EXPECT_HR(hr, S_OK);
+
+ hr = IMXAttributes_addAttribute(
+ mx_attributes, _bstr_("uri"), _bstr_("local"),
+ _bstr_("branch"), _bstr_("type"), _bstr_("Japan")
+ );
+ EXPECT_HR(hr, S_OK);
+
+ hr = IMXAttributes_QueryInterface(mx_attributes, &IID_ISAXAttributes, (void**)&sax_attributes);
+ EXPECT_HR(hr, S_OK);
+
+ hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"Number", 6, sax_attributes);
+ EXPECT_HR(hr, S_OK);
+
+ ISAXAttributes_Release(sax_attributes);
+ IMXAttributes_Release(mx_attributes);
+
+ hr = ISAXContentHandler_characters(content, L"12345", 5);
+ EXPECT_HR(hr, S_OK);
+
+ hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"Number", 6);
+ EXPECT_HR(hr, S_OK);
+
+ /* <Name>Captain Ahab</Name> */
+ hr = ISAXContentHandler_startElement(content, L"", 0, L"", 0, L"Name", 4, NULL);
+ EXPECT_HR(hr, S_OK);
+
+ hr = ISAXContentHandler_characters(content, L"Captain Ahab", 12);
+ EXPECT_HR(hr, S_OK);
+
+ hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"Name", 4);
+ EXPECT_HR(hr, S_OK);
+
+ /* </BankAccount> */
+ hr = ISAXContentHandler_endElement(content, L"", 0, L"", 0, L"BankAccount", 11);
+ EXPECT_HR(hr, S_OK);
+
+ hr = ISAXContentHandler_endDocument(content);
+ EXPECT_HR(hr, S_OK);
+
+
+ /* Assert that it created the correct document */
+ hr = IXMLDOMDocument3_get_documentElement(domdoc, &root);
+ EXPECT_HR(hr, S_OK);
+
+ /* <BankAccount> */
+ hr = IXMLDOMElement_get_nodeName(root, &str);
+ EXPECT_HR(hr, S_OK);
+ ok(!lstrcmpW(L"BankAccount", str), "got %s\n", wine_dbgstr_w(str));
+ SysFreeString(str);
+
+ hr = IXMLDOMElement_get_childNodes(root, &node_list);
+ EXPECT_HR(hr, S_OK);
+
+ hr = IXMLDOMNodeList_get_length(node_list, &list_length);
+ EXPECT_HR(hr, S_OK);
+ ok(2 == list_length, "list length %i, expected 1\n", list_length);
+
+ /* <Number */
+ hr = IXMLDOMNodeList_get_item(node_list, 0, &node);
+ EXPECT_HR(hr, S_OK);
+
+ hr = IXMLDOMNode_get_nodeName(node, &str);
+ EXPECT_HR(hr, S_OK);
+ ok(!lstrcmpW(L"Number", str), "got %s\n", wine_dbgstr_w(str));
+ SysFreeString(str);
+
+ hr = IXMLDOMNode_get_attributes(node, &attribute_map);
+ EXPECT_HR(hr, S_OK);
+
+ hr = IXMLDOMNamedNodeMap_get_length(attribute_map, &list_length);
+ EXPECT_HR(hr, S_OK);
+ ok(2 == list_length, "attributes length %i, expected 2\n", list_length);
+
+ /* bank="World Bank" */
+ hr = IXMLDOMNamedNodeMap_get_item(attribute_map, 0, &attribute_node);
+ EXPECT_HR(hr, S_OK);
+
+ hr = IXMLDOMNode_get_nodeName(attribute_node, &str);
+ EXPECT_HR(hr, S_OK);
+ ok(!lstrcmpW(L"bank", str), "got %s\n", wine_dbgstr_w(str));
+ SysFreeString(str);
+
+ hr = IXMLDOMNode_get_text(attribute_node, &str);
+ EXPECT_HR(hr, S_OK);
+ ok(!lstrcmpW(L"World Bank", str), "got %s\n", wine_dbgstr_w(str));
+ SysFreeString(str);
+ IXMLDOMNode_Release(attribute_node);
+
+ /* branch="Japan" */
+ hr = IXMLDOMNamedNodeMap_get_item(attribute_map, 1, &attribute_node);
+ EXPECT_HR(hr, S_OK);
+
+ hr = IXMLDOMNode_get_nodeName(attribute_node, &str);
+ EXPECT_HR(hr, S_OK);
+ ok(!lstrcmpW(L"branch", str), "got %s\n", wine_dbgstr_w(str));
+ SysFreeString(str);
+
+ hr = IXMLDOMNode_get_text(attribute_node, &str);
+ EXPECT_HR(hr, S_OK);
+ ok(!lstrcmpW(L"Japan", str), "got %s\n", wine_dbgstr_w(str));
+ SysFreeString(str);
+ IXMLDOMNode_Release(attribute_node);
+ IXMLDOMNamedNodeMap_Release(attribute_map);
+
+ /* >12345</Number> */
+ hr = IXMLDOMNode_get_text(node, &str);
+ EXPECT_HR(hr, S_OK);
+ ok(!lstrcmpW(L"12345", str), "got %s\n", wine_dbgstr_w(str));
+ SysFreeString(str);
+
+ IXMLDOMNode_Release(node);
+
+ /* <Name>Captain Ahab</Name></BankAccount> */
+ hr = IXMLDOMNodeList_get_item(node_list, 1, &node);
+ EXPECT_HR(hr, S_OK);
+
+ hr = IXMLDOMNode_get_nodeName(node, &str);
+ EXPECT_HR(hr, S_OK);
+ ok(!lstrcmpW(L"Name", str), "got %s\n", wine_dbgstr_w(str));
+ SysFreeString(str);
+
+ hr = IXMLDOMNode_get_text(node, &str);
+ EXPECT_HR(hr, S_OK);
+ ok(!lstrcmpW(L"Captain Ahab", str), "got %s\n", wine_dbgstr_w(str));
+ SysFreeString(str);
+ IXMLDOMNode_Release(node);
+ IXMLDOMNodeList_Release(node_list);
+ IXMLDOMElement_Release(root);
+
+ /* finally test doc output */
+ hr = IXMLDOMDocument3_get_xml(domdoc, &str);
+ EXPECT_HR(hr, S_OK);
+ todo_wine ok(
+ !lstrcmpW(
+ L"<?targ type=\"test sheet\" test=\"something\"?>\r\n"
+ "<BankAccount>"
+ "<Number bank=\"World Bank\" branch=\"Japan\">12345</Number>"
+ "<Name>Captain Ahab</Name>"
+ "</BankAccount>\r\n",
+ str),
+ "got %s\n", wine_dbgstr_w(str));
+ SysFreeString(str);
+
+ IDispatch_Release(dispatch);
+ IXMLDOMDocument3_Release(domdoc);
+ ISAXContentHandler_Release(content);
+ IMXWriter_Release(writer);
+
+ free_bstrs();
+}
+
static const char *encoding_names[] = {
"iso-8859-1",
"iso-8859-2",
@@ -5768,6 +5984,7 @@ START_TEST(saxreader)
test_mxwriter_properties();
test_mxwriter_flush();
test_mxwriter_stream();
+ test_mxwriter_domdoc();
test_mxwriter_encoding();
test_mxwriter_dispex();
test_mxwriter_indent();
--
2.26.2
More information about the wine-devel
mailing list