aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--debugXML.c3
-rw-r--r--parser.c216
-rw-r--r--result/att1018
-rw-r--r--result/att10.rde23
-rw-r--r--result/att10.rdr23
-rw-r--r--result/att10.sax61
-rw-r--r--result/att10.sax257
-rw-r--r--result/att119
-rw-r--r--result/att11.rde2
-rw-r--r--result/att11.rdr2
-rw-r--r--result/att11.sax21
-rw-r--r--result/att11.sax220
-rw-r--r--result/att96
-rw-r--r--result/att9.rde2
-rw-r--r--result/att9.rdr2
-rw-r--r--result/att9.sax9
-rw-r--r--result/att9.sax29
-rw-r--r--result/c14n/with-comments/example-42
-rw-r--r--result/c14n/without-comments/example-42
-rw-r--r--result/noent/att1018
-rw-r--r--result/noent/att119
-rw-r--r--result/noent/att96
-rw-r--r--test/att1022
-rw-r--r--test/att1113
-rw-r--r--test/att95
26 files changed, 519 insertions, 52 deletions
diff --git a/ChangeLog b/ChangeLog
index e8eea45f..fef03637 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+Tue Mar 25 17:48:02 CET 2008 Daniel Veillard <daniel@veillard.com>
+
+ * parser.c: fix various attribute normalisation problems reported
+ by Ashwin
+ * result/c14n/without-comments/example-4
+ result/c14n/with-comments/example-4: this impacted the result of
+ two c14n tests :-\
+ * test/att9 test/att10 test/att11 result//att9* result//att10*
+ result//att11*: added 3 specific regression tests coming from the
+ XML spec revision and from Ashwin
+
Tue Mar 25 14:20:49 CET 2008 Daniel Veillard <daniel@veillard.com>
* uri.c: fix saving for file:///X:/ URI embedding Windows file paths
diff --git a/debugXML.c b/debugXML.c
index f66f5964..de6fd6c7 100644
--- a/debugXML.c
+++ b/debugXML.c
@@ -320,7 +320,8 @@ xmlCtxtGenericNodeCheck(xmlDebugCtxtPtr ctxt, xmlNodePtr node) {
}
if (node->next == NULL) {
if ((node->parent != NULL) && (node->type != XML_ATTRIBUTE_NODE) &&
- (node->parent->last != node))
+ (node->parent->last != node) &&
+ (node->parent->type == XML_ELEMENT_NODE))
xmlDebugErr(ctxt, XML_CHECK_NO_NEXT,
"Node has no next and not last of parent list\n");
} else {
diff --git a/parser.c b/parser.c
index 69b1caf1..80e6b695 100644
--- a/parser.c
+++ b/parser.c
@@ -863,6 +863,103 @@ struct _xmlDefAttrs {
};
/**
+ * xmlAttrNormalizeSpace:
+ * @src: the source string
+ * @dst: the target string
+ *
+ * Normalize the space in non CDATA attribute values:
+ * If the attribute type is not CDATA, then the XML processor MUST further
+ * process the normalized attribute value by discarding any leading and
+ * trailing space (#x20) characters, and by replacing sequences of space
+ * (#x20) characters by a single space (#x20) character.
+ * Note that the size of dst need to be at least src, and if one doesn't need
+ * to preserve dst (and it doesn't come from a dictionary or read-only) then
+ * passing src as dst is just fine.
+ *
+ * Returns a pointer to the normalized value (dst) or NULL if no conversion
+ * is needed.
+ */
+static xmlChar *
+xmlAttrNormalizeSpace(const xmlChar *src, xmlChar *dst)
+{
+ if ((src == NULL) || (dst == NULL))
+ return(NULL);
+
+ while (*src == 0x20) src++;
+ while (*src != 0) {
+ if (*src == 0x20) {
+ while (*src == 0x20) src++;
+ if (*src != 0)
+ *dst++ = 0x20;
+ } else {
+ *dst++ = *src++;
+ }
+ }
+ *dst = 0;
+ if (dst == src)
+ return(NULL);
+ return(dst);
+}
+
+/**
+ * xmlAttrNormalizeSpace2:
+ * @src: the source string
+ *
+ * Normalize the space in non CDATA attribute values, a slightly more complex
+ * front end to avoid allocation problems when running on attribute values
+ * coming from the input.
+ *
+ * Returns a pointer to the normalized value (dst) or NULL if no conversion
+ * is needed.
+ */
+static const xmlChar *
+xmlAttrNormalizeSpace2(xmlParserCtxtPtr ctxt, const xmlChar *src, int *len)
+{
+ int i;
+ int remove_head = 0;
+ int need_realloc = 0;
+ const xmlChar *cur;
+
+ if ((ctxt == NULL) || (src == NULL) || (len == NULL))
+ return(NULL);
+ i = *len;
+ if (i <= 0)
+ return(NULL);
+
+ cur = src;
+ while (*cur == 0x20) {
+ cur++;
+ remove_head++;
+ }
+ while (*cur != 0) {
+ if (*cur == 0x20) {
+ cur++;
+ if ((*cur == 0x20) || (*cur == 0)) {
+ need_realloc = 1;
+ break;
+ }
+ } else
+ cur++;
+ }
+ if (need_realloc) {
+ xmlChar *ret;
+
+ ret = xmlStrndup(src + remove_head, i - remove_head + 1);
+ if (ret == NULL) {
+ xmlErrMemory(ctxt, NULL);
+ return(NULL);
+ }
+ xmlAttrNormalizeSpace(ret, ret);
+ *len = (int) strlen((const char *)ret);
+ return(ret);
+ } else if (remove_head) {
+ *len -= remove_head;
+ return(src + remove_head);
+ }
+ return(NULL);
+}
+
+/**
* xmlAddDefAttrs:
* @ctxt: an XML parser context
* @fullname: the element fullname
@@ -5020,6 +5117,8 @@ xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
xmlFreeEnumeration(tree);
break;
}
+ if ((type != XML_ATTRIBUTE_CDATA) && (defaultValue != NULL))
+ xmlAttrNormalizeSpace(defaultValue, defaultValue);
GROW;
if (RAW != '>') {
@@ -7900,9 +7999,10 @@ need_complex:
static const xmlChar *
xmlParseAttribute2(xmlParserCtxtPtr ctxt,
- const xmlChar *pref, const xmlChar *elem,
- const xmlChar **prefix, xmlChar **value,
- int *len, int *alloc) {
+ const xmlChar * pref, const xmlChar * elem,
+ const xmlChar ** prefix, xmlChar ** value,
+ int *len, int *alloc)
+{
const xmlChar *name;
xmlChar *val, *internal_val = NULL;
int normalize = 0;
@@ -7911,9 +8011,9 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt,
GROW;
name = xmlParseQName(ctxt, prefix);
if (name == NULL) {
- xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED,
- "error parsing attribute name\n");
- return(NULL);
+ xmlFatalErrMsg(ctxt, XML_ERR_NAME_REQUIRED,
+ "error parsing attribute name\n");
+ return (NULL);
}
/*
@@ -7923,8 +8023,9 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt,
int type;
type = (int) (long) xmlHashQLookup2(ctxt->attsSpecial,
- pref, elem, *prefix, name);
- if (type != 0) normalize = 1;
+ pref, elem, *prefix, name);
+ if (type != 0)
+ normalize = 1;
}
/*
@@ -7933,54 +8034,71 @@ xmlParseAttribute2(xmlParserCtxtPtr ctxt,
SKIP_BLANKS;
if (RAW == '=') {
NEXT;
- SKIP_BLANKS;
- val = xmlParseAttValueInternal(ctxt, len, alloc, normalize);
- ctxt->instate = XML_PARSER_CONTENT;
+ SKIP_BLANKS;
+ val = xmlParseAttValueInternal(ctxt, len, alloc, normalize);
+ if (normalize) {
+ /*
+ * Sometimes a second normalisation pass for spaces is needed
+ * but that only happens if charrefs or entities refernces
+ * have been used in the attribute value, i.e. the attribute
+ * value have been extracted in an allocated string already.
+ */
+ if (*alloc) {
+ const xmlChar *val2;
+
+ val2 = xmlAttrNormalizeSpace2(ctxt, val, len);
+ if (val2 != NULL) {
+ xmlFree(val);
+ val = val2;
+ }
+ }
+ }
+ ctxt->instate = XML_PARSER_CONTENT;
} else {
- xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE,
- "Specification mandate value for attribute %s\n", name);
- return(NULL);
+ xmlFatalErrMsgStr(ctxt, XML_ERR_ATTRIBUTE_WITHOUT_VALUE,
+ "Specification mandate value for attribute %s\n",
+ name);
+ return (NULL);
}
- if (*prefix == ctxt->str_xml) {
- /*
- * Check that xml:lang conforms to the specification
- * No more registered as an error, just generate a warning now
- * since this was deprecated in XML second edition
- */
- if ((ctxt->pedantic) && (xmlStrEqual(name, BAD_CAST "lang"))) {
- internal_val = xmlStrndup(val, *len);
- if (!xmlCheckLanguageID(internal_val)) {
- xmlWarningMsg(ctxt, XML_WAR_LANG_VALUE,
- "Malformed value for xml:lang : %s\n",
- internal_val, NULL);
- }
- }
+ if (*prefix == ctxt->str_xml) {
+ /*
+ * Check that xml:lang conforms to the specification
+ * No more registered as an error, just generate a warning now
+ * since this was deprecated in XML second edition
+ */
+ if ((ctxt->pedantic) && (xmlStrEqual(name, BAD_CAST "lang"))) {
+ internal_val = xmlStrndup(val, *len);
+ if (!xmlCheckLanguageID(internal_val)) {
+ xmlWarningMsg(ctxt, XML_WAR_LANG_VALUE,
+ "Malformed value for xml:lang : %s\n",
+ internal_val, NULL);
+ }
+ }
- /*
- * Check that xml:space conforms to the specification
- */
- if (xmlStrEqual(name, BAD_CAST "space")) {
- internal_val = xmlStrndup(val, *len);
- if (xmlStrEqual(internal_val, BAD_CAST "default"))
- *(ctxt->space) = 0;
- else if (xmlStrEqual(internal_val, BAD_CAST "preserve"))
- *(ctxt->space) = 1;
- else {
- xmlWarningMsg(ctxt, XML_WAR_SPACE_VALUE,
-"Invalid value \"%s\" for xml:space : \"default\" or \"preserve\" expected\n",
- internal_val, NULL);
- }
- }
- if (internal_val) {
- xmlFree(internal_val);
- }
- }
+ /*
+ * Check that xml:space conforms to the specification
+ */
+ if (xmlStrEqual(name, BAD_CAST "space")) {
+ internal_val = xmlStrndup(val, *len);
+ if (xmlStrEqual(internal_val, BAD_CAST "default"))
+ *(ctxt->space) = 0;
+ else if (xmlStrEqual(internal_val, BAD_CAST "preserve"))
+ *(ctxt->space) = 1;
+ else {
+ xmlWarningMsg(ctxt, XML_WAR_SPACE_VALUE,
+ "Invalid value \"%s\" for xml:space : \"default\" or \"preserve\" expected\n",
+ internal_val, NULL);
+ }
+ }
+ if (internal_val) {
+ xmlFree(internal_val);
+ }
+ }
*value = val;
- return(name);
+ return (name);
}
-
/**
* xmlParseStartTag2:
* @ctxt: an XML parser context
diff --git a/result/att10 b/result/att10
new file mode 100644
index 00000000..5b29bf82
--- /dev/null
+++ b/result/att10
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ELEMENT doc (tst)*>
+<!ELEMENT tst (#PCDATA)>
+<!ATTLIST tst a NMTOKENS #IMPLIED>
+<!ATTLIST tst b CDATA #IMPLIED>
+<!ENTITY d "&#xD;">
+<!ENTITY a "&#xA;">
+<!ENTITY da "&#xD;&#xA;">
+]>
+<doc>
+<tst a="xyz" b=" xyz"/>
+<tst a="&d;&d;A&a; &a;B&da;" b="&d;&d;A&a; &a;B&da;"/>
+<tst a="&#13;&#13;A&#10;&#10;B&#13;&#10;" b="&#13;&#13;A&#10;&#10;B&#13;&#10;"/>
+<tst a="x y" b=" x y "/>
+<tst a="a b" b=" a b "/>
+<tst a="a b" b=" a b "/>
+</doc>
diff --git a/result/att10.rde b/result/att10.rde
new file mode 100644
index 00000000..2ca79054
--- /dev/null
+++ b/result/att10.rde
@@ -0,0 +1,23 @@
+0 10 doc 0 0
+0 1 doc 0 0
+1 14 #text 0 1
+
+1 1 tst 1 0
+1 14 #text 0 1
+
+1 1 tst 1 0
+1 14 #text 0 1
+
+1 1 tst 1 0
+1 14 #text 0 1
+
+1 1 tst 1 0
+1 14 #text 0 1
+
+1 1 tst 1 0
+1 14 #text 0 1
+
+1 1 tst 1 0
+1 14 #text 0 1
+
+0 15 doc 0 0
diff --git a/result/att10.rdr b/result/att10.rdr
new file mode 100644
index 00000000..2ca79054
--- /dev/null
+++ b/result/att10.rdr
@@ -0,0 +1,23 @@
+0 10 doc 0 0
+0 1 doc 0 0
+1 14 #text 0 1
+
+1 1 tst 1 0
+1 14 #text 0 1
+
+1 1 tst 1 0
+1 14 #text 0 1
+
+1 1 tst 1 0
+1 14 #text 0 1
+
+1 1 tst 1 0
+1 14 #text 0 1
+
+1 1 tst 1 0
+1 14 #text 0 1
+
+1 1 tst 1 0
+1 14 #text 0 1
+
+0 15 doc 0 0
diff --git a/result/att10.sax b/result/att10.sax
new file mode 100644
index 00000000..2df49a57
--- /dev/null
+++ b/result/att10.sax
@@ -0,0 +1,61 @@
+SAX.setDocumentLocator()
+SAX.startDocument()
+SAX.internalSubset(doc, , )
+SAX.elementDecl(doc, 4, ...)
+SAX.elementDecl(tst, 3, ...)
+SAX.attributeDecl(tst, a, 8, 3, NULL, ...)
+SAX.attributeDecl(tst, b, 1, 3, NULL, ...)
+SAX.entityDecl(d, 1, (null), (null), )
+SAX.getEntity(d)
+SAX.entityDecl(a, 1, (null), (null),
+)
+SAX.getEntity(a)
+SAX.entityDecl(da, 1, (null), (null),
+)
+SAX.getEntity(da)
+SAX.externalSubset(doc, , )
+SAX.startElement(doc)
+SAX.characters(
+, 1)
+SAX.startElement(tst, a=' xyz', b=' xyz')
+SAX.endElement(tst)
+SAX.characters(
+, 1)
+SAX.getEntity(d)
+SAX.getEntity(d)
+SAX.getEntity(a)
+SAX.getEntity(a)
+SAX.getEntity(da)
+SAX.getEntity(d)
+SAX.getEntity(d)
+SAX.getEntity(a)
+SAX.getEntity(a)
+SAX.getEntity(da)
+SAX.startElement(tst, a='&d;&d;A&a; &a;B&da;', b='&d;&d;A&a; &a;B&da;')
+SAX.endElement(tst)
+SAX.characters(
+, 1)
+SAX.startElement(tst, a=' A
+
+B
+', b=' A
+
+B
+')
+SAX.endElement(tst)
+SAX.characters(
+, 1)
+SAX.startElement(tst, a=' x y ', b=' x y ')
+SAX.endElement(tst)
+SAX.characters(
+, 1)
+SAX.startElement(tst, a=' a b ', b=' a b ')
+SAX.endElement(tst)
+SAX.characters(
+, 1)
+SAX.startElement(tst, a=' a b ', b=' a b ')
+SAX.endElement(tst)
+SAX.characters(
+, 1)
+SAX.endElement(doc)
+SAX.endDocument()
diff --git a/result/att10.sax2 b/result/att10.sax2
new file mode 100644
index 00000000..7c6f61de
--- /dev/null
+++ b/result/att10.sax2
@@ -0,0 +1,57 @@
+SAX.setDocumentLocator()
+SAX.startDocument()
+SAX.internalSubset(doc, , )
+SAX.elementDecl(doc, 4, ...)
+SAX.elementDecl(tst, 3, ...)
+SAX.attributeDecl(tst, a, 8, 3, NULL, ...)
+SAX.attributeDecl(tst, b, 1, 3, NULL, ...)
+SAX.entityDecl(d, 1, (null), (null), )
+SAX.getEntity(d)
+SAX.entityDecl(a, 1, (null), (null),
+)
+SAX.getEntity(a)
+SAX.entityDecl(da, 1, (null), (null),
+)
+SAX.getEntity(da)
+SAX.externalSubset(doc, , )
+SAX.startElementNs(doc, NULL, NULL, 0, 0, 0)
+SAX.characters(
+, 1)
+SAX.startElementNs(tst, NULL, NULL, 0, 2, 0, a='xyz"...', 3, b=' xy...', 5)
+SAX.endElementNs(tst, NULL, NULL)
+SAX.characters(
+, 1)
+SAX.getEntity(d)
+SAX.getEntity(d)
+SAX.getEntity(a)
+SAX.getEntity(a)
+SAX.getEntity(da)
+SAX.getEntity(d)
+SAX.getEntity(d)
+SAX.getEntity(a)
+SAX.getEntity(a)
+SAX.getEntity(da)
+SAX.startElementNs(tst, NULL, NULL, 0, 2, 0, a='&d;&...', 19, b='&d;&...', 19)
+SAX.endElementNs(tst, NULL, NULL)
+SAX.characters(
+, 1)
+SAX.startElementNs(tst, NULL, NULL, 0, 2, 0, a=' A
+...', 8, b=' A
+...', 8)
+SAX.endElementNs(tst, NULL, NULL)
+SAX.characters(
+, 1)
+SAX.startElementNs(tst, NULL, NULL, 0, 2, 0, a='x y...', 3, b=' x ...', 6)
+SAX.endElementNs(tst, NULL, NULL)
+SAX.characters(
+, 1)
+SAX.startElementNs(tst, NULL, NULL, 0, 2, 0, a='a b ...', 3, b=' a b...', 5)
+SAX.endElementNs(tst, NULL, NULL)
+SAX.characters(
+, 1)
+SAX.startElementNs(tst, NULL, NULL, 0, 2, 0, a='a b...', 3, b=' a ...', 8)
+SAX.endElementNs(tst, NULL, NULL)
+SAX.characters(
+, 1)
+SAX.endElementNs(doc, NULL, NULL)
+SAX.endDocument()
diff --git a/result/att11 b/result/att11
new file mode 100644
index 00000000..121b06df
--- /dev/null
+++ b/result/att11
@@ -0,0 +1,9 @@
+<?xml version="1.0" standalone="yes"?>
+<!DOCTYPE attributes [
+<!ELEMENT attributes EMPTY>
+<!ATTLIST attributes nmtoken NMTOKEN #IMPLIED>
+<!ATTLIST attributes nmtokens NMTOKENS #IMPLIED>
+<!ENTITY ent " entity&recursive; ">
+<!ENTITY recursive "reference">
+]>
+<attributes nmtoken="&ent; &ent; &ent;" nmtokens="Test&#13;&#10; this normalization"/>
diff --git a/result/att11.rde b/result/att11.rde
new file mode 100644
index 00000000..cc83bea4
--- /dev/null
+++ b/result/att11.rde
@@ -0,0 +1,2 @@
+0 10 attributes 0 0
+0 1 attributes 1 0
diff --git a/result/att11.rdr b/result/att11.rdr
new file mode 100644
index 00000000..cc83bea4
--- /dev/null
+++ b/result/att11.rdr
@@ -0,0 +1,2 @@
+0 10 attributes 0 0
+0 1 attributes 1 0
diff --git a/result/att11.sax b/result/att11.sax
new file mode 100644
index 00000000..67dcf22d
--- /dev/null
+++ b/result/att11.sax
@@ -0,0 +1,21 @@
+SAX.setDocumentLocator()
+SAX.startDocument()
+SAX.internalSubset(attributes, , )
+SAX.elementDecl(attributes, 1, ...)
+SAX.attributeDecl(attributes, nmtoken, 7, 3, NULL, ...)
+SAX.attributeDecl(attributes, nmtokens, 8, 3, NULL, ...)
+SAX.entityDecl(ent, 1, (null), (null), entity&recursive; )
+SAX.getEntity(ent)
+SAX.entityDecl(recursive, 1, (null), (null), reference)
+SAX.getEntity(recursive)
+SAX.externalSubset(attributes, , )
+SAX.getEntity(ent)
+SAX.getEntity(recursive)
+SAX.getEntity(ent)
+SAX.getEntity(recursive)
+SAX.getEntity(ent)
+SAX.getEntity(recursive)
+SAX.startElement(attributes, nmtoken=' &ent; &ent; &ent; ', nmtokens=' Test
+ this normalization ')
+SAX.endElement(attributes)
+SAX.endDocument()
diff --git a/result/att11.sax2 b/result/att11.sax2
new file mode 100644
index 00000000..859a9704
--- /dev/null
+++ b/result/att11.sax2
@@ -0,0 +1,20 @@
+SAX.setDocumentLocator()
+SAX.startDocument()
+SAX.internalSubset(attributes, , )
+SAX.elementDecl(attributes, 1, ...)
+SAX.attributeDecl(attributes, nmtoken, 7, 3, NULL, ...)
+SAX.attributeDecl(attributes, nmtokens, 8, 3, NULL, ...)
+SAX.entityDecl(ent, 1, (null), (null), entity&recursive; )
+SAX.getEntity(ent)
+SAX.entityDecl(recursive, 1, (null), (null), reference)
+SAX.getEntity(recursive)
+SAX.externalSubset(attributes, , )
+SAX.getEntity(ent)
+SAX.getEntity(recursive)
+SAX.getEntity(ent)
+SAX.getEntity(recursive)
+SAX.getEntity(ent)
+SAX.getEntity(recursive)
+SAX.startElementNs(attributes, NULL, NULL, 0, 2, 0, nmtoken='&ent...', 17, nmtokens='Test...', 25)
+SAX.endElementNs(attributes, NULL, NULL)
+SAX.endDocument()
diff --git a/result/att9 b/result/att9
new file mode 100644
index 00000000..e4982a29
--- /dev/null
+++ b/result/att9
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ATTLIST doc a1 NMTOKENS "1 2">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc/>
diff --git a/result/att9.rde b/result/att9.rde
new file mode 100644
index 00000000..9b0a34db
--- /dev/null
+++ b/result/att9.rde
@@ -0,0 +1,2 @@
+0 10 doc 0 0
+0 1 doc 1 0
diff --git a/result/att9.rdr b/result/att9.rdr
new file mode 100644
index 00000000..9b0a34db
--- /dev/null
+++ b/result/att9.rdr
@@ -0,0 +1,2 @@
+0 10 doc 0 0
+0 1 doc 1 0
diff --git a/result/att9.sax b/result/att9.sax
new file mode 100644
index 00000000..0fe14a14
--- /dev/null
+++ b/result/att9.sax
@@ -0,0 +1,9 @@
+SAX.setDocumentLocator()
+SAX.startDocument()
+SAX.internalSubset(doc, , )
+SAX.attributeDecl(doc, a1, 8, 1, 1 2, ...)
+SAX.elementDecl(doc, 3, ...)
+SAX.externalSubset(doc, , )
+SAX.startElement(doc)
+SAX.endElement(doc)
+SAX.endDocument()
diff --git a/result/att9.sax2 b/result/att9.sax2
new file mode 100644
index 00000000..09b3a04c
--- /dev/null
+++ b/result/att9.sax2
@@ -0,0 +1,9 @@
+SAX.setDocumentLocator()
+SAX.startDocument()
+SAX.internalSubset(doc, , )
+SAX.attributeDecl(doc, a1, 8, 1, 1 2, ...)
+SAX.elementDecl(doc, 3, ...)
+SAX.externalSubset(doc, , )
+SAX.startElementNs(doc, NULL, NULL, 0, 1, 1, a1='1 2...', 3)
+SAX.endElementNs(doc, NULL, NULL)
+SAX.endDocument()
diff --git a/result/c14n/with-comments/example-4 b/result/c14n/with-comments/example-4
index 26937c87..19a25592 100644
--- a/result/c14n/with-comments/example-4
+++ b/result/c14n/with-comments/example-4
@@ -5,5 +5,5 @@ Second line</text>
<compute>value&gt;"0" &amp;&amp; value&lt;"10" ?"valid":"error"</compute>
<compute expr="value>&quot;0&quot; &amp;&amp; value&lt;&quot;10&quot; ?&quot;valid&quot;:&quot;error&quot;">valid</compute>
<norm attr=" ' &#xD;&#xA;&#x9; ' "></norm>
- <normId id="' &#xD;&#xA;&#x9; '"></normId>
+ <normId id="' &#xD;&#xA;&#x9; '"></normId>
</doc> \ No newline at end of file
diff --git a/result/c14n/without-comments/example-4 b/result/c14n/without-comments/example-4
index 26937c87..19a25592 100644
--- a/result/c14n/without-comments/example-4
+++ b/result/c14n/without-comments/example-4
@@ -5,5 +5,5 @@ Second line</text>
<compute>value&gt;"0" &amp;&amp; value&lt;"10" ?"valid":"error"</compute>
<compute expr="value>&quot;0&quot; &amp;&amp; value&lt;&quot;10&quot; ?&quot;valid&quot;:&quot;error&quot;">valid</compute>
<norm attr=" ' &#xD;&#xA;&#x9; ' "></norm>
- <normId id="' &#xD;&#xA;&#x9; '"></normId>
+ <normId id="' &#xD;&#xA;&#x9; '"></normId>
</doc> \ No newline at end of file
diff --git a/result/noent/att10 b/result/noent/att10
new file mode 100644
index 00000000..cc1c6b0a
--- /dev/null
+++ b/result/noent/att10
@@ -0,0 +1,18 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ELEMENT doc (tst)*>
+<!ELEMENT tst (#PCDATA)>
+<!ATTLIST tst a NMTOKENS #IMPLIED>
+<!ATTLIST tst b CDATA #IMPLIED>
+<!ENTITY d "&#xD;">
+<!ENTITY a "&#xA;">
+<!ENTITY da "&#xD;&#xA;">
+]>
+<doc>
+<tst a="xyz" b=" xyz"/>
+<tst a="&#13;&#13;A&#10; &#10;B&#13;&#10;" b="&#13;&#13;A&#10; &#10;B&#13;&#10;"/>
+<tst a="&#13;&#13;A&#10;&#10;B&#13;&#10;" b="&#13;&#13;A&#10;&#10;B&#13;&#10;"/>
+<tst a="x y" b=" x y "/>
+<tst a="a b" b=" a b "/>
+<tst a="a b" b=" a b "/>
+</doc>
diff --git a/result/noent/att11 b/result/noent/att11
new file mode 100644
index 00000000..3646e62b
--- /dev/null
+++ b/result/noent/att11
@@ -0,0 +1,9 @@
+<?xml version="1.0" standalone="yes"?>
+<!DOCTYPE attributes [
+<!ELEMENT attributes EMPTY>
+<!ATTLIST attributes nmtoken NMTOKEN #IMPLIED>
+<!ATTLIST attributes nmtokens NMTOKENS #IMPLIED>
+<!ENTITY ent " entity&recursive; ">
+<!ENTITY recursive "reference">
+]>
+<attributes nmtoken="entityreference entityreference entityreference" nmtokens="Test&#13;&#10; this normalization"/>
diff --git a/result/noent/att9 b/result/noent/att9
new file mode 100644
index 00000000..e4982a29
--- /dev/null
+++ b/result/noent/att9
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<!DOCTYPE doc [
+<!ATTLIST doc a1 NMTOKENS "1 2">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc/>
diff --git a/test/att10 b/test/att10
new file mode 100644
index 00000000..5c14dc69
--- /dev/null
+++ b/test/att10
@@ -0,0 +1,22 @@
+<!DOCTYPE doc [
+<!ELEMENT doc (tst*)>
+<!ELEMENT tst (#PCDATA)>
+<!ATTLIST tst a NMTOKENS #IMPLIED>
+<!ATTLIST tst b CDATA #IMPLIED>
+<!ENTITY d "&#xD;">
+<!ENTITY a "&#xA;">
+<!ENTITY da "&#xD;&#xA;">
+]>
+<doc>
+<tst a="
+
+xyz" b="
+
+xyz"/>
+<tst a="&d;&d;A&a;&#x20;&a;B&da;" b="&d;&d;A&a;&#x20;&a;B&da;"/>
+<tst a="&#xd;&#xd;A&#xa;&#xa;B&#xd;&#xa;" b="&#xd;&#xd;A&#xa;&#xa;B&#xd;&#xa;"/>
+<tst a="&#32;x&#32;&#32;y&#32;" b="&#32;x&#32;&#32;y&#32;"/>
+<tst a=" a b " b=" a b "/>
+<tst a=" a b " b=" a b "/>
+</doc>
+
diff --git a/test/att11 b/test/att11
new file mode 100644
index 00000000..32faaf30
--- /dev/null
+++ b/test/att11
@@ -0,0 +1,13 @@
+<?xml version='1.0' standalone='yes'?>
+<!DOCTYPE attributes [
+<!ELEMENT attributes EMPTY>
+<!ATTLIST attributes
+ nmtoken NMTOKEN #IMPLIED
+ nmtokens NMTOKENS #IMPLIED>
+<!ENTITY ent " entity&recursive; ">
+<!ENTITY recursive "reference">
+]>
+<attributes
+ nmtoken = " &ent; &ent; &ent; "
+ nmtokens = " Test&#x0d;&#x0a; this&#x20; normalization "
+/>
diff --git a/test/att9 b/test/att9
new file mode 100644
index 00000000..f06b531a
--- /dev/null
+++ b/test/att9
@@ -0,0 +1,5 @@
+<!DOCTYPE doc [
+<!ATTLIST doc a1 NMTOKENS " 1 2 ">
+<!ELEMENT doc (#PCDATA)>
+]>
+<doc/>