xmllite/reader: Implement MoveToAttributeByName().

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2017-07-21 15:00:03 +03:00 committed by Alexandre Julliard
parent e1983836b7
commit be5679108c
2 changed files with 205 additions and 67 deletions

View file

@ -521,6 +521,19 @@ static void reader_clear_elements(xmlreader *reader)
reader->is_empty_element = FALSE;
}
static struct ns *reader_lookup_ns(xmlreader *reader, const strval *prefix)
{
struct list *nslist = prefix ? &reader->ns : &reader->nsdef;
struct ns *ns;
LIST_FOR_EACH_ENTRY_REV(ns, nslist, struct ns, entry) {
if (strval_eq(reader, prefix, &ns->prefix))
return ns;
}
return NULL;
}
static HRESULT reader_inc_depth(xmlreader *reader)
{
return (++reader->depth >= reader->max_depth && reader->max_depth) ? SC_E_MAXELEMENTDEPTH : S_OK;
@ -2989,12 +3002,110 @@ static HRESULT WINAPI xmlreader_MoveToNextAttribute(IXmlReader* iface)
return next ? S_OK : S_FALSE;
}
static HRESULT WINAPI xmlreader_MoveToAttributeByName(IXmlReader* iface,
LPCWSTR local_name,
LPCWSTR namespaceUri)
static void reader_get_attribute_ns_uri(xmlreader *reader, struct attribute *attr, const WCHAR **uri, UINT *len)
{
FIXME("(%p %p %p): stub\n", iface, local_name, namespaceUri);
return E_NOTIMPL;
static const WCHAR xmlns_uriW[] = {'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/',
'2','0','0','0','/','x','m','l','n','s','/',0};
static const WCHAR xml_uriW[] = {'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/',
'X','M','L','/','1','9','9','8','/','n','a','m','e','s','p','a','c','e',0};
/* Check for reserved prefixes first */
if ((strval_eq(reader, &attr->prefix, &strval_empty) && strval_eq(reader, &attr->localname, &strval_xmlns)) ||
strval_eq(reader, &attr->prefix, &strval_xmlns))
{
*uri = xmlns_uriW;
*len = sizeof(xmlns_uriW)/sizeof(xmlns_uriW[0]) - 1;
}
else if (strval_eq(reader, &attr->prefix, &strval_xml))
{
*uri = xml_uriW;
*len = sizeof(xml_uriW)/sizeof(xml_uriW[0]) - 1;
}
else
{
*uri = NULL;
*len = 0;
}
if (!*uri)
{
struct ns *ns;
if ((ns = reader_lookup_ns(reader, &attr->prefix)))
{
*uri = ns->uri.str;
*len = ns->uri.len;
}
else
{
*uri = emptyW;
*len = 0;
}
}
}
static void reader_get_attribute_local_name(xmlreader *reader, struct attribute *attr, const WCHAR **name, UINT *len)
{
if (attr->flags & ATTRIBUTE_DEFAULT_NS_DEFINITION)
{
*name = xmlnsW;
*len = 5;
}
else if (attr->flags & ATTRIBUTE_NS_DEFINITION)
{
const struct ns *ns = reader_lookup_ns(reader, &attr->localname);
*name = ns->prefix.str;
*len = ns->prefix.len;
}
else
{
*name = attr->localname.str;
*len = attr->localname.len;
}
}
static HRESULT WINAPI xmlreader_MoveToAttributeByName(IXmlReader* iface,
const WCHAR *local_name, const WCHAR *namespace_uri)
{
xmlreader *This = impl_from_IXmlReader(iface);
UINT target_name_len, target_uri_len;
struct attribute *attr;
TRACE("(%p)->(%s %s)\n", This, debugstr_w(local_name), debugstr_w(namespace_uri));
if (!local_name)
return E_INVALIDARG;
if (!This->attr_count)
return S_FALSE;
if (!namespace_uri)
namespace_uri = emptyW;
target_name_len = strlenW(local_name);
target_uri_len = strlenW(namespace_uri);
LIST_FOR_EACH_ENTRY(attr, &This->attrs, struct attribute, entry)
{
UINT name_len, uri_len;
const WCHAR *name, *uri;
reader_get_attribute_local_name(This, attr, &name, &name_len);
reader_get_attribute_ns_uri(This, attr, &uri, &uri_len);
if (name_len == target_name_len && uri_len == target_uri_len &&
!strcmpW(name, local_name) && !strcmpW(uri, namespace_uri))
{
This->attr = attr;
This->chunk_read_off = 0;
reader_set_strvalue(This, StringValue_Prefix, &This->attr->prefix);
reader_set_strvalue(This, StringValue_QualifiedName, &This->attr->qname);
reader_set_strvalue(This, StringValue_Value, &This->attr->value);
return S_OK;
}
}
return S_FALSE;
}
static HRESULT WINAPI xmlreader_MoveToElement(IXmlReader* iface)
@ -3088,19 +3199,6 @@ static HRESULT WINAPI xmlreader_GetQualifiedName(IXmlReader* iface, LPCWSTR *nam
return S_OK;
}
static struct ns *reader_lookup_ns(xmlreader *reader, const strval *prefix)
{
struct list *nslist = prefix ? &reader->ns : &reader->nsdef;
struct ns *ns;
LIST_FOR_EACH_ENTRY_REV(ns, nslist, struct ns, entry) {
if (strval_eq(reader, prefix, &ns->prefix))
return ns;
}
return NULL;
}
static struct ns *reader_lookup_nsdef(xmlreader *reader)
{
if (list_empty(&reader->nsdef))
@ -3122,42 +3220,10 @@ static HRESULT WINAPI xmlreader_GetNamespaceUri(IXmlReader* iface, const WCHAR *
if (!len)
len = &length;
*uri = NULL;
*len = 0;
switch ((nodetype = reader_get_nodetype(This)))
{
case XmlNodeType_Attribute:
{
static const WCHAR xmlns_uriW[] = {'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/',
'2','0','0','0','/','x','m','l','n','s','/',0};
static const WCHAR xml_uriW[] = {'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/',
'X','M','L','/','1','9','9','8','/','n','a','m','e','s','p','a','c','e',0};
/* check for reserved prefixes first */
if ((strval_eq(This, prefix, &strval_empty) && strval_eq(This, &This->attr->localname, &strval_xmlns)) ||
strval_eq(This, prefix, &strval_xmlns))
{
*uri = xmlns_uriW;
*len = sizeof(xmlns_uriW)/sizeof(xmlns_uriW[0]) - 1;
}
else if (strval_eq(This, prefix, &strval_xml)) {
*uri = xml_uriW;
*len = sizeof(xml_uriW)/sizeof(xml_uriW[0]) - 1;
}
if (!*uri) {
ns = reader_lookup_ns(This, prefix);
if (ns) {
*uri = ns->uri.str;
*len = ns->uri.len;
}
else {
*uri = emptyW;
*len = 0;
}
}
}
reader_get_attribute_ns_uri(This, This->attr, uri, len);
break;
case XmlNodeType_Element:
case XmlNodeType_EndElement:
@ -3189,6 +3255,8 @@ static HRESULT WINAPI xmlreader_GetNamespaceUri(IXmlReader* iface, const WCHAR *
break;
default:
FIXME("Unhandled node type %d\n", nodetype);
*uri = NULL;
*len = 0;
return E_NOTIMPL;
}
@ -3222,22 +3290,7 @@ static HRESULT WINAPI xmlreader_GetLocalName(IXmlReader* iface, LPCWSTR *name, U
*len = element->localname.len;
break;
case XmlNodeType_Attribute:
if (This->attr->flags & ATTRIBUTE_DEFAULT_NS_DEFINITION)
{
*name = xmlnsW;
*len = 5;
}
else if (This->attr->flags & ATTRIBUTE_NS_DEFINITION)
{
const struct ns *ns = reader_lookup_ns(This, &This->attr->localname);
*name = ns->prefix.str;
*len = ns->prefix.len;
}
else
{
*name = This->attr->localname.str;
*len = This->attr->localname.len;
}
reader_get_attribute_local_name(This, This->attr, name, len);
break;
default:
*name = This->strvalues[StringValue_LocalName].str;

View file

@ -2571,6 +2571,90 @@ static void test_string_pointers(void)
IXmlReader_Release(reader);
}
static void test_attribute_by_name(void)
{
static const char *xml = "<a><elem xmlns=\"myns\" a=\"value a\" b=\"value b\" xmlns:ns=\"ns uri\" "
"ns:c=\"value c\" c=\"value c2\"/></a>";
static const WCHAR xmlns_uriW[] = {'h','t','t','p',':','/','/','w','w','w','.','w','3','.','o','r','g','/',
'2','0','0','0','/','x','m','l','n','s','/',0};
static const WCHAR nsuriW[] = {'n','s',' ','u','r','i',0};
static const WCHAR xmlnsW[] = {'x','m','l','n','s',0};
static const WCHAR mynsW[] = {'m','y','n','s',0};
static const WCHAR nsW[] = {'n','s',0};
static const WCHAR emptyW[] = {0};
static const WCHAR aW[] = {'a',0};
static const WCHAR bW[] = {'b',0};
static const WCHAR cW[] = {'c',0};
IXmlReader *reader;
HRESULT hr;
hr = CreateXmlReader(&IID_IXmlReader, (void **)&reader, NULL);
ok(hr == S_OK, "Failed to create reader, hr %#x.\n", hr);
set_input_string(reader, xml);
hr = IXmlReader_MoveToAttributeByName(reader, NULL, NULL);
ok(hr == E_INVALIDARG || broken(hr == S_FALSE) /* WinXP */, "Unexpected hr %#x.\n", hr);
hr = IXmlReader_MoveToAttributeByName(reader, emptyW, NULL);
ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
read_node(reader, XmlNodeType_Element);
hr = IXmlReader_MoveToAttributeByName(reader, emptyW, NULL);
ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
read_node(reader, XmlNodeType_Element);
hr = IXmlReader_MoveToAttributeByName(reader, NULL, NULL);
ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
hr = IXmlReader_MoveToAttributeByName(reader, NULL, xmlns_uriW);
ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
hr = IXmlReader_MoveToAttributeByName(reader, emptyW, xmlns_uriW);
ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
hr = IXmlReader_MoveToAttributeByName(reader, xmlnsW, NULL);
ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
hr = IXmlReader_MoveToAttributeByName(reader, xmlnsW, xmlns_uriW);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
reader_value(reader, "myns");
hr = IXmlReader_MoveToAttributeByName(reader, aW, NULL);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
reader_value(reader, "value a");
hr = IXmlReader_MoveToAttributeByName(reader, bW, NULL);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
reader_value(reader, "value b");
hr = IXmlReader_MoveToAttributeByName(reader, aW, mynsW);
ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
hr = IXmlReader_MoveToAttributeByName(reader, nsW, NULL);
ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
hr = IXmlReader_MoveToAttributeByName(reader, nsW, xmlns_uriW);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
reader_value(reader, "ns uri");
hr = IXmlReader_MoveToAttributeByName(reader, bW, emptyW);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
reader_value(reader, "value b");
hr = IXmlReader_MoveToAttributeByName(reader, cW, NULL);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
reader_value(reader, "value c2");
hr = IXmlReader_MoveToAttributeByName(reader, cW, nsuriW);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
reader_value(reader, "value c");
IXmlReader_Release(reader);
}
START_TEST(reader)
{
test_reader_create();
@ -2598,4 +2682,5 @@ START_TEST(reader)
test_max_element_depth();
test_reader_position();
test_string_pointers();
test_attribute_by_name();
}