xmllite: Initial implementation of attribute parsing.
This commit is contained in:
parent
ccf04d644b
commit
53f72826a2
|
@ -1757,37 +1757,129 @@ static HRESULT reader_parse_qname(xmlreader *reader, strval *prefix, strval *loc
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
/* [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
|
||||
[67] Reference ::= EntityRef | CharRef
|
||||
[68] EntityRef ::= '&' Name ';' */
|
||||
static HRESULT reader_parse_reference(xmlreader *reader)
|
||||
{
|
||||
FIXME("References not supported\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
/* [10 NS] AttValue ::= '"' ([^<&"] | Reference)* '"' | "'" ([^<&'] | Reference)* "'" */
|
||||
static HRESULT reader_parse_attvalue(xmlreader *reader, strval *value)
|
||||
{
|
||||
WCHAR *ptr, *start;
|
||||
WCHAR quote;
|
||||
|
||||
ptr = reader_get_cur(reader);
|
||||
|
||||
/* skip opening quote */
|
||||
quote = *ptr;
|
||||
if (quote != '\"' && quote != '\'') return WC_E_QUOTE;
|
||||
reader_skipn(reader, 1);
|
||||
|
||||
start = ptr = reader_get_cur(reader);
|
||||
while (*ptr)
|
||||
{
|
||||
if (*ptr == '<') return WC_E_LESSTHAN;
|
||||
|
||||
if (*ptr == quote)
|
||||
{
|
||||
/* skip closing quote */
|
||||
reader_skipn(reader, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
if (*ptr == '&')
|
||||
{
|
||||
HRESULT hr = reader_parse_reference(reader);
|
||||
if (FAILED(hr)) return hr;
|
||||
}
|
||||
else
|
||||
reader_skipn(reader, 1);
|
||||
ptr = reader_get_cur(reader);
|
||||
}
|
||||
|
||||
reader_init_strvalue(start, ptr-start, value);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* [1 NS] NSAttName ::= PrefixedAttName | DefaultAttName
|
||||
[2 NS] PrefixedAttName ::= 'xmlns:' NCName
|
||||
[3 NS] DefaultAttName ::= 'xmlns'
|
||||
[15 NS] Attribute ::= NSAttName Eq AttValue | QName Eq AttValue */
|
||||
static HRESULT reader_parse_attribute(xmlreader *reader)
|
||||
{
|
||||
static const WCHAR xmlnsW[] = {'x','m','l','n','s',0};
|
||||
strval prefix, local, qname, xmlns, value;
|
||||
HRESULT hr;
|
||||
|
||||
hr = reader_parse_qname(reader, &prefix, &local, &qname);
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
reader_init_strvalue((WCHAR*)xmlnsW, 5, &xmlns);
|
||||
|
||||
if (strval_eq(&prefix, &xmlns))
|
||||
{
|
||||
FIXME("namespace definitions not supported\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
if (strval_eq(&qname, &xmlns))
|
||||
{
|
||||
FIXME("default namespace definitions not supported\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
hr = reader_parse_eq(reader);
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
hr = reader_parse_attvalue(reader, &value);
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
TRACE("%s=\"%s\"\n", debugstr_wn(local.str, local.len), debugstr_wn(value.str, value.len));
|
||||
return reader_add_attr(reader, &local, &value);
|
||||
}
|
||||
|
||||
/* [12 NS] STag ::= '<' QName (S Attribute)* S? '>'
|
||||
[14 NS] EmptyElemTag ::= '<' QName (S Attribute)* S? '/>' */
|
||||
static HRESULT reader_parse_stag(xmlreader *reader, strval *prefix, strval *local, strval *qname, int *empty)
|
||||
{
|
||||
static const WCHAR endW[] = {'/','>',0};
|
||||
HRESULT hr;
|
||||
|
||||
hr = reader_parse_qname(reader, prefix, local, qname);
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
reader_skipspaces(reader);
|
||||
|
||||
/* empty element */
|
||||
if ((*empty = !reader_cmp(reader, endW)))
|
||||
while (1)
|
||||
{
|
||||
/* skip '/>' */
|
||||
reader_skipn(reader, 2);
|
||||
reader->empty_element = TRUE;
|
||||
return S_OK;
|
||||
static const WCHAR endW[] = {'/','>',0};
|
||||
|
||||
reader_skipspaces(reader);
|
||||
|
||||
/* empty element */
|
||||
if ((*empty = !reader_cmp(reader, endW)))
|
||||
{
|
||||
/* skip '/>' */
|
||||
reader_skipn(reader, 2);
|
||||
reader->empty_element = TRUE;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* got a start tag */
|
||||
if (!reader_cmp(reader, gtW))
|
||||
{
|
||||
/* skip '>' */
|
||||
reader_skipn(reader, 1);
|
||||
return reader_push_element(reader, qname);
|
||||
}
|
||||
|
||||
hr = reader_parse_attribute(reader);
|
||||
if (FAILED(hr)) return hr;
|
||||
}
|
||||
|
||||
/* got a start tag */
|
||||
if (!reader_cmp(reader, gtW))
|
||||
{
|
||||
/* skip '>' */
|
||||
reader_skipn(reader, 1);
|
||||
return reader_push_element(reader, qname);
|
||||
}
|
||||
|
||||
FIXME("only empty elements/start tags without attribute list supported\n");
|
||||
return E_NOTIMPL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
/* [39] element ::= EmptyElemTag | STag content ETag */
|
||||
|
@ -1937,15 +2029,6 @@ static HRESULT reader_parse_cdata(xmlreader *reader)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
/* [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
|
||||
[67] Reference ::= EntityRef | CharRef
|
||||
[68] EntityRef ::= '&' Name ';' */
|
||||
static HRESULT reader_parse_reference(xmlreader *reader)
|
||||
{
|
||||
FIXME("References not supported\n");
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
/* [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) */
|
||||
static HRESULT reader_parse_chardata(xmlreader *reader)
|
||||
{
|
||||
|
|
|
@ -1566,6 +1566,93 @@ static void test_isemptyelement(void)
|
|||
IXmlReader_Release(reader);
|
||||
}
|
||||
|
||||
static struct test_entry attributes_tests[] = {
|
||||
{ "<a attr1=\"attrvalue\"/>", "attr1", "attrvalue", S_OK },
|
||||
{ "<a attr1=\"a\'\'ttrvalue\"/>", "attr1", "a\'\'ttrvalue", S_OK },
|
||||
{ "<a attr1=\'a\"ttrvalue\'/>", "attr1", "a\"ttrvalue", S_OK },
|
||||
{ "<a attr1=\' \'/>", "attr1", " ", S_OK },
|
||||
{ "<a attr1=\" \"/>", "attr1", " ", S_OK },
|
||||
{ "<a attr1=attrvalue/>", NULL, NULL, WC_E_QUOTE },
|
||||
{ "<a attr1=\"attr<value\"/>", NULL, NULL, WC_E_LESSTHAN },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static void test_read_attribute(void)
|
||||
{
|
||||
struct test_entry *test = attributes_tests;
|
||||
IXmlReader *reader;
|
||||
HRESULT hr;
|
||||
|
||||
hr = pCreateXmlReader(&IID_IXmlReader, (void**)&reader, NULL);
|
||||
ok(hr == S_OK, "S_OK, got %08x\n", hr);
|
||||
|
||||
while (test->xml)
|
||||
{
|
||||
XmlNodeType type;
|
||||
IStream *stream;
|
||||
|
||||
stream = create_stream_on_data(test->xml, strlen(test->xml)+1);
|
||||
hr = IXmlReader_SetInput(reader, (IUnknown*)stream);
|
||||
ok(hr == S_OK, "got %08x\n", hr);
|
||||
|
||||
type = XmlNodeType_None;
|
||||
hr = IXmlReader_Read(reader, &type);
|
||||
|
||||
if (test->hr_broken)
|
||||
ok(hr == test->hr || broken(hr == test->hr_broken), "got %08x for %s\n", hr, test->xml);
|
||||
else
|
||||
ok(hr == test->hr, "got %08x for %s\n", hr, test->xml);
|
||||
if (hr == S_OK)
|
||||
{
|
||||
const WCHAR *str;
|
||||
WCHAR *str_exp;
|
||||
UINT len;
|
||||
|
||||
ok(type == XmlNodeType_Element, "got %d for %s\n", type, test->xml);
|
||||
|
||||
hr = IXmlReader_MoveToFirstAttribute(reader);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
|
||||
len = 1;
|
||||
str = NULL;
|
||||
hr = IXmlReader_GetLocalName(reader, &str, &len);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
todo_wine {
|
||||
ok(len == strlen(test->name), "got %u\n", len);
|
||||
str_exp = a2w(test->name);
|
||||
ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
|
||||
free_str(str_exp);
|
||||
}
|
||||
len = 1;
|
||||
str = NULL;
|
||||
hr = IXmlReader_GetQualifiedName(reader, &str, &len);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
todo_wine {
|
||||
ok(len == strlen(test->name), "got %u\n", len);
|
||||
str_exp = a2w(test->name);
|
||||
ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
|
||||
free_str(str_exp);
|
||||
}
|
||||
/* value */
|
||||
len = 1;
|
||||
str = NULL;
|
||||
hr = IXmlReader_GetValue(reader, &str, &len);
|
||||
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||
todo_wine {
|
||||
ok(len == strlen(test->value), "got %u\n", len);
|
||||
str_exp = a2w(test->value);
|
||||
ok(!lstrcmpW(str, str_exp), "got %s\n", wine_dbgstr_w(str));
|
||||
free_str(str_exp);
|
||||
}
|
||||
}
|
||||
|
||||
IStream_Release(stream);
|
||||
test++;
|
||||
}
|
||||
|
||||
IXmlReader_Release(reader);
|
||||
}
|
||||
|
||||
START_TEST(reader)
|
||||
{
|
||||
HRESULT r;
|
||||
|
@ -1582,6 +1669,7 @@ START_TEST(reader)
|
|||
test_reader_create();
|
||||
test_readerinput();
|
||||
test_reader_state();
|
||||
test_read_attribute();
|
||||
test_read_cdata();
|
||||
test_read_comment();
|
||||
test_read_pi();
|
||||
|
|
Loading…
Reference in New Issue