formats: std/xml reads the internal subset: entities, default attributes and an expansion limit (step 2 of #78) #552
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Step 2 of the epic #78 (
std/xml). Step 1 (#429) landed the tree, the reader and the writer, and the reader refuses a document type declaration with an internal subset, because reading one means declaring entities. This step reads the internal subset, so that a document that declares its own entities and default attributes is read correctly, with an expansion limit so that a hostile document is anXmlErrorand not an out-of-memory panic, and with no external entity or DTD ever fetched or opened.Source
doctype()and scanner,reference(): the two places that refuse today.std/yaml'saliasLimit(yaml.trb, docs) is the model for the limit.Design record point
ENCODING.md section 16 point 16 (this issue changes it from "refused" to "read") and ROADMAP "Which versions a format supports". Touches the seed? No: the compiler does not import
std/xmland no std name is looked up by string.Scope
In:
SYSTEM/PUBLICand unparsedNDATAones are declared and recorded), parameter entity declarations and their references between declarations, attribute-list declarations, and<!ELEMENT>/<!NOTATION>declarations, comments and processing instructions, which are checked for well-formedness and otherwise skipped (no validation).<!ATTLIST>are added to an element that does not carry them (#FIXEDand plain defaults;#REQUIRED/#IMPLIEDadd nothing), and a declared tokenised type (ID,NMTOKEN, enumerations, ...) normalises the value as section 3.3.3 says. The first declaration of an attribute wins. A defaultedxmlns/xmlns:pattribute takes part in namespace resolution.entityLimit: IntonXml(decision, default 1000000): the total number of characters that references to declared entities add to one document. Exceeding it is anXmlErrorthat names the option, likealiasLimit. Recursion (<!ENTITY a "&a;">, directly or in a cycle) is the well-formedness error "No Recursion", never a loop.SYSTEM/PUBLICidentifier on the doctype) is kept as theDoctypenode's identifiers and not read; a reference to an external or unparsed entity in content or an attribute value is anXmlErrorthat says the entity is not read (decision: error, not skip, since skipping would read the rest of the document wrongly). A reference to an entity that is not declared is an error as before, and the message says when the document has an external subset that this reader does not read.Doctypenode keeps its name and identifiers and does not keep the subset (decision); entity references are resolved and not kept (ENCODING.md point 15).Xml.writetherefore writes the doctype without a subset, andparse(write(tree)) == treestill holds for every treeparsemade, defaults included, which are explicit attributes by then.XmlErrorfor a problem inside an expansion reports the position of the reference in the document.Out: validation of any kind (content models,
IDuniqueness,IDREFresolution); reading an external subset or external entity; XML 1.1; the typed binding (step 3) and the mapping DSL (step 4).Acceptance criteria
&name;in text and in attribute values reads as the replacement text, an entity with markup in its value yields the elements, and a default attribute shows up inattributes()and inattribute(local).XmlErrornamingentityLimitand finish quickly; raisingentityLimitlets a legitimate larger document through. A self-referencing and a mutually recursive entity are anXmlError.<!ENTITY x SYSTEM "file:///some/path">and&x;) is anXmlErrorand nothing is opened: a test shows no file read happens (no file system or network access in the package, as in step 1).std/xml/tests/conformance-cases.trb, each named by its production or constraint like the existing ones: DeclSep and markupdecl placement,PE Between Declarations,PEs in Internal Subset,Entity Declared,Parsed Entity,No Recursion,No External Entity References,No < in Attribute Values,Legal Characterin a replacement text,Well-Formed Parsed Entity(unbalanced replacement text),Unique Att Specwith defaults, plus the namespace constraints on a defaultedxmlns. The W3C suite itself cannot be redistributed (seestd/xml/tests/NOTICE.md); the cases are written from the Recommendation, and NOTICE.md is updated where it says cases that need a DTD are not covered.parse(write(tree)) == treeholds for a parsed document with an internal subset.docs/standard-library/xml.md(the "What the reader does" paragraph, theXmldeclaration block withentityLimit, the sentence "refuses an internal subset" in the summary), the doc comments inxml.trb/parser.trb, ENCODING.md section 16 point 16 and the slice 8 status row, ROADMAP only if its XML line needs the wording;skills/regenerated.torb format --checkon touched files, tier A/B and gates green in forge CI.Size
One PR, two Conventional Commits, a std package change and no compiler change:
feat(xml): read the internal subset and expand declared entities(subset reader, entity table, expansion in content and attribute values,entityLimit, recursion and external-entity errors, tests);feat(xml): add the default attributes of an attribute-list declaration(ATTLIST, defaults, tokenised-type normalisation, namespace interplay, tests, docs).Estimate: 4 to 6 h of work, about 600 lines of parser and tests (the step 1 reader is 436 lines).
Dependencies
Encode/Decode); the WebDAV (#67) ands3:(#20) drivers need only step 1 for their replies and are not blocked by this one.Part of #78.
std/xml#78std/xml#78[loop:torbscript] claim implement by session:loop-torbscript-20261028 until 2026-10-28T23:06:32Z
[loop:torbscript] implement: std/xml reads the internal subset of the DOCTYPE (entities, ATTLIST defaults, entityLimit, tests, docs, skills); PR #554 is open, bootstrap is green and the rest of CI is queued on the runners, next: waiting (CI queue)
Xml.decodereads a document into a typed value (step 3a of #78) #570std/xml#78Xml.encodewrites a typed value as an XML document (step 3b of #78) #605