From 009b53c4a958fd751686ea185b006fa1a383b703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?cel=20=F0=9F=8C=B8?= Date: Sat, 2 Nov 2024 01:48:54 +0000 Subject: [PATCH] implement XML composers --- src/xml/composers.rs | 796 ++++++++++++++++++++++++++++++++++++++++++- src/xml/mod.rs | 9 +- src/xml/parsers.rs | 8 +- 3 files changed, 788 insertions(+), 25 deletions(-) diff --git a/src/xml/composers.rs b/src/xml/composers.rs index 3313a56..949bb65 100644 --- a/src/xml/composers.rs +++ b/src/xml/composers.rs @@ -3,12 +3,18 @@ use std::io; use tokio::io::{AsyncWrite, AsyncWriteExt}; use super::{ - AttValue, AttValueData, CDEnd, CDSect, CDStart, CData, Char, CharData, Comment, DeclSep, - DefaultAttName, DoctypeDecl, Document, Element, EntityValue, EntityValueData, Eq, ExtSubset, - ExtSubsetDecl, IntSubset, LocalPart, MarkupDecl, Misc, NCName, NSAttName, Name, NameChar, - NameStartChar, Names, Nmtoken, Nmtokens, PITarget, Prefix, PrefixedAttName, PrefixedName, - Prolog, PubidChar, PubidLiteral, QName, SDDecl, SystemLiteral, UnprefixedName, VersionInfo, - VersionNum, XMLDecl, PI, S, + AttDef, AttDefName, AttType, AttValue, AttValueData, AttlistDecl, Attribute, CDEnd, CDSect, + CDStart, CData, Char, CharData, CharRef, Children, ChildrenKind, Choice, Comment, + ConditionalSect, Content, ContentItem, Contentspec, Cp, CpKind, DeclSep, DefaultAttName, + DefaultDecl, DoctypeDecl, Document, ETag, Element, Elementdecl, EmptyElemTag, EncName, + EncodingDecl, EntityDecl, EntityDef, EntityRef, EntityValue, EntityValueData, EnumeratedType, + Enumeration, Eq, ExtParsedEnt, ExtSubset, ExtSubsetDecl, ExtSubsetDeclaration, ExternalID, + GEDecl, Ignore, IgnoreSect, IgnoreSectContents, IncludeSect, IntSubset, LocalPart, MarkupDecl, + Misc, Mixed, NCName, NDataDecl, NSAttName, Name, NameChar, NameStartChar, Names, Nmtoken, + Nmtokens, NotationDecl, NotationDeclID, NotationType, Occurence, PEDecl, PEDef, PEReference, + PITarget, Prefix, PrefixedAttName, PrefixedName, Prolog, PubidChar, PubidLiteral, PublicID, + QName, Reference, SDDecl, STag, Seq, StringType, SystemLiteral, TextDecl, TokenizedType, + UnprefixedName, VersionInfo, VersionNum, XMLDecl, PI, S, }; /// Compact Composer trait, can create different trait later for pretty composition @@ -508,10 +514,10 @@ impl<'s> Composer<'s> for XMLDecl<'s> { { writer.write_all("".as_bytes()).await?; @@ -594,11 +600,11 @@ impl<'s> Composer<'s> for DoctypeDecl<'s> { writer.write_all(" Composer<'s> for ExtSubset<'s> { where W: Unpin + AsyncWrite, { - if let Some(text_decl) = self.text_decl { + if let Some(text_decl) = &self.text_decl { text_decl.write(writer).await? } self.ext_subset_decl.write(writer).await?; @@ -680,13 +686,11 @@ impl<'s> Composer<'s> for ExtSubsetDecl<'s> { { for declaration in self { match declaration { - super::ExtSubsetDeclaration::MarkupDecl(markup_decl) => { - markup_decl.write(writer).await? + ExtSubsetDeclaration::MarkupDecl(markup_decl) => markup_decl.write(writer).await?, + ExtSubsetDeclaration::ConditionalSect(conditional_sect) => { + Box::pin(conditional_sect.write(writer)).await? } - super::ExtSubsetDeclaration::ConditionalSect(conditional_sect) => { - conditional_sect.write(writer).await? - } - super::ExtSubsetDeclaration::DeclSep(decl_sep) => decl_sep.write(writer).await?, + ExtSubsetDeclaration::DeclSep(decl_sep) => decl_sep.write(writer).await?, } } Ok(()) @@ -724,12 +728,768 @@ impl Composer<'_> for SDDecl { } } +// (Productions 33 through 38 have been removed.) + /// [39] element ::= EmptyElemTag | STag content ETag impl<'s> Composer<'s> for Element<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { - todo!() + match self { + Element::Empty(empty_elem_tag) => empty_elem_tag.write(writer).await?, + Element::NotEmpty(s_tag, content, e_tag) => { + s_tag.write(writer).await?; + content.write(writer).await?; + e_tag.write(writer).await?; + } + } + Ok(()) + } +} + +/// [12] STag ::= '<' QName (S Attribute)* S? '>' +/// [40] STag ::= '<' Name (S Attribute)* S? '>' +impl<'s> Composer<'s> for STag<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("<".as_bytes()).await?; + self.name.write(writer).await?; + for attribute in &self.attributes { + S.write(writer).await?; + attribute.write(writer).await?; + } + writer.write_all(">".as_bytes()).await?; + Ok(()) + } +} + +/// [15] Attribute ::= NSAttName Eq AttValue | QName Eq AttValue +impl<'s> Composer<'s> for Attribute<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + Attribute::NamespaceDeclaration { ns_name, value } => { + ns_name.write(writer).await?; + Eq.write(writer).await?; + value.write(writer).await?; + } + Attribute::Attribute { name, value } => { + name.write(writer).await?; + Eq.write(writer).await?; + value.write(writer).await?; + } + } + Ok(()) + } +} + +/// [13] ETag ::= '' +impl<'s> Composer<'s> for ETag<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("".as_bytes()).await?; + Ok(()) + } +} + +/// [43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)* +impl<'s> Composer<'s> for Content<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + if let Some(char_data) = &self.char_data { + char_data.write(writer).await?; + } + for (content, char_data) in &self.content { + match content { + ContentItem::Element(element) => Box::pin(element.write(writer)).await?, + ContentItem::Reference(reference) => reference.write(writer).await?, + ContentItem::CDSect(cd_sect) => cd_sect.write(writer).await?, + ContentItem::PI(pi) => pi.write(writer).await?, + ContentItem::Comment(comment) => comment.write(writer).await?, + } + if let Some(char_data) = char_data { + char_data.write(writer).await?; + } + } + Ok(()) + } +} + +/// [14] EmptyElemTag ::= '<' QName (S Attribute)* S? '/>' +impl<'s> Composer<'s> for EmptyElemTag<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("<".as_bytes()).await?; + self.name.write(writer).await?; + for attribute in &self.attributes { + S.write(writer).await?; + attribute.write(writer).await?; + } + writer.write_all("/>".as_bytes()).await?; + Ok(()) + } +} + +/// [17] elementdecl ::= '' +impl<'s> Composer<'s> for Elementdecl<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("".as_bytes()).await?; + Ok(()) + } +} + +/// [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children +impl<'s> Composer<'s> for Contentspec<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + Contentspec::Empty => writer.write_all("EMPTY".as_bytes()).await?, + Contentspec::Any => writer.write_all("ANY".as_bytes()).await?, + Contentspec::Mixed(mixed) => mixed.write(writer).await?, + Contentspec::Children(children) => children.write(writer).await?, + } + Ok(()) + } +} + +/// Occurence ::= ('?' | '*' | '+')? +impl Composer<'_> for Occurence { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + Occurence::Once => {} + Occurence::Optional => writer.write_all("?".as_bytes()).await?, + Occurence::Many0 => writer.write_all("*".as_bytes()).await?, + Occurence::Many1 => writer.write_all("+".as_bytes()).await?, + } + Ok(()) + } +} + +/// [47] children ::= (choice | seq) ('?' | '*' | '+')? +impl<'s> Composer<'s> for Children<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match &self.kind { + ChildrenKind::Choice(choice) => choice.write(writer).await?, + ChildrenKind::Seq(seq) => seq.write(writer).await?, + } + self.occurence.write(writer).await?; + Ok(()) + } +} + +/// [18] cp ::= (QName | choice | seq) ('?' | '*' | '+')? +impl<'s> Composer<'s> for Cp<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match &self.kind { + CpKind::Name(q_name) => q_name.write(writer).await?, + CpKind::Choice(choice) => Box::pin(choice.write(writer)).await?, + CpKind::Seq(seq) => Box::pin(seq.write(writer)).await?, + } + self.occurence.write(writer).await?; + Ok(()) + } +} + +/// [49] choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')' +impl<'s> Composer<'s> for Choice<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("(".as_bytes()).await?; + let mut first = true; + for cp in &self.0 { + if !first { + writer.write_all("|".as_bytes()).await?; + } + cp.write(writer).await?; + if first { + first = false + } + } + writer.write_all(")".as_bytes()).await?; + Ok(()) + } +} + +/// [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')' +impl<'s> Composer<'s> for Seq<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("(".as_bytes()).await?; + let mut first = true; + for cp in &self.0 { + if !first { + writer.write_all(",".as_bytes()).await?; + } + cp.write(writer).await?; + if first { + first = false + } + } + writer.write_all(")".as_bytes()).await?; + Ok(()) + } +} + +/// [19] Mixed ::= '(' S? '#PCDATA' (S? '|' S? QName)* S? ')*' | '(' S? '#PCDATA' S? ')' +impl<'s> Composer<'s> for Mixed<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("(#PCDATA".as_bytes()).await?; + if !self.0.is_empty() { + for q_name in &self.0 { + writer.write_all("|".as_bytes()).await?; + q_name.write(writer).await?; + } + writer.write_all(")*".as_bytes()).await?; + } else { + writer.write_all(")".as_bytes()).await?; + } + Ok(()) + } +} + +/// [20] AttlistDecl ::= '' +impl<'s> Composer<'s> for AttlistDecl<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("".as_bytes()).await?; + Ok(()) + } +} + +/// [21] AttDef ::= S (QName | NSAttName) S AttType S DefaultDecl +impl<'s> Composer<'s> for AttDef<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + S.write(writer).await?; + match &self.name { + AttDefName::QName(q_name) => q_name.write(writer).await?, + AttDefName::NSAttName(ns_att_name) => ns_att_name.write(writer).await?, + } + S.write(writer).await?; + self.att_type.write(writer).await?; + S.write(writer).await?; + self.default_decl.write(writer).await?; + Ok(()) + } +} + +/// [54] AttType ::= StringType | TokenizedType | EnumeratedType +impl<'s> Composer<'s> for AttType<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + AttType::StringType => StringType.write(writer).await?, + AttType::TokenizedType(tokenized_type) => tokenized_type.write(writer).await?, + AttType::EnumeratedType(enumerated_type) => enumerated_type.write(writer).await?, + } + Ok(()) + } +} + +/// [55] StringType ::= 'CDATA' +impl Composer<'_> for StringType { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("CDATA".as_bytes()).await?; + Ok(()) + } +} + +/// [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' | 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS' +impl Composer<'_> for TokenizedType { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + TokenizedType::ID => writer.write_all("ID".as_bytes()).await?, + TokenizedType::IDRef => writer.write_all("IDREF".as_bytes()).await?, + TokenizedType::IDRefs => writer.write_all("IDREFS".as_bytes()).await?, + TokenizedType::Entity => writer.write_all("ENTITY".as_bytes()).await?, + TokenizedType::Entities => writer.write_all("ENTITIES".as_bytes()).await?, + TokenizedType::NMToken => writer.write_all("NMTOKEN".as_bytes()).await?, + TokenizedType::NMTokens => writer.write_all("NMTOKENS".as_bytes()).await?, + } + Ok(()) + } +} + +/// [57] EnumeratedType ::= NotationType | Enumeration +impl<'s> Composer<'s> for EnumeratedType<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + EnumeratedType::NotationType(notation_type) => notation_type.write(writer).await?, + EnumeratedType::Enumeration(enumeration) => enumeration.write(writer).await?, + } + Ok(()) + } +} + +/// [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')' +impl<'s> Composer<'s> for NotationType<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("NOTATION".as_bytes()).await?; + S.write(writer).await?; + writer.write_all("(".as_bytes()).await?; + let mut first = true; + for name in &self.0 { + if !first { + writer.write_all("|".as_bytes()).await?; + } + name.write(writer).await?; + if first { + first = false + } + } + writer.write_all(")".as_bytes()).await?; + Ok(()) + } +} + +/// [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' +impl<'s> Composer<'s> for Enumeration<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("(".as_bytes()).await?; + let mut first = true; + for nm_token in &self.0 { + if !first { + writer.write_all("|".as_bytes()).await?; + } + nm_token.write(writer).await?; + if first { + first = false + } + } + writer.write_all(")".as_bytes()).await?; + Ok(()) + } +} + +/// [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue) +impl<'s> Composer<'s> for DefaultDecl<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + DefaultDecl::Required => writer.write_all("#REQUIRED".as_bytes()).await?, + DefaultDecl::Implied => writer.write_all("#IMPLIED".as_bytes()).await?, + DefaultDecl::Fixed(fixed, att_value) => { + if *fixed { + writer.write_all("#FIXED".as_bytes()).await?; + S.write(writer).await?; + } + att_value.write(writer).await? + } + } + Ok(()) + } +} + +/// [61] conditionalSect ::= includeSect | ignoreSect +impl<'s> Composer<'s> for ConditionalSect<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + ConditionalSect::IncludeSect(include_sect) => include_sect.write(writer).await?, + ConditionalSect::IgnoreSect(ignore_sect) => ignore_sect.write(writer).await?, + } + Ok(()) + } +} + +/// [62] includeSect ::= '' +impl<'s> Composer<'s> for IncludeSect<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("".as_bytes()).await?; + Ok(()) + } +} + +/// [63] ignoreSect ::= '' +impl<'s> Composer<'s> for IgnoreSect<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("".as_bytes()).await?; + Ok(()) + } +} + +/// [64] ignoreSectContents ::= Ignore ('' Ignore)* +impl<'s> Composer<'s> for IgnoreSectContents<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + self.ignore.write(writer).await?; + for (ignore_sect_contents, ignore) in &self.ignore_list { + writer.write_all("".as_bytes()).await?; + ignore.write(writer).await?; + } + Ok(()) + } +} + +/// [65] Ignore ::= Char* - (Char* ('') Char*) +impl<'s> Composer<'s> for Ignore<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all(self.0.as_bytes()).await?; + Ok(()) + } +} + +/// [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';' +impl<'s> Composer<'s> for CharRef<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + CharRef::Decimal(decimal) => { + writer.write_all("&#".as_bytes()).await?; + writer.write_all(decimal.as_bytes()).await?; + writer.write_all(";".as_bytes()).await?; + } + CharRef::Hexadecimal(hexadecimal) => { + writer.write_all("&#x".as_bytes()).await?; + writer.write_all(hexadecimal.as_bytes()).await?; + writer.write_all(";".as_bytes()).await?; + } + } + Ok(()) + } +} + +/// [67] Reference ::= EntityRef | CharRef +impl<'s> Composer<'s> for Reference<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + Reference::EntityRef(entity_ref) => entity_ref.write(writer).await?, + Reference::CharRef(char_ref) => char_ref.write(writer).await?, + } + Ok(()) + } +} + +/// [68] EntityRef ::= '&' Name ';' +impl<'s> Composer<'s> for EntityRef<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("&".as_bytes()).await?; + self.0.write(writer).await?; + writer.write_all(";".as_bytes()).await?; + Ok(()) + } +} + +/// [69] PEReference ::= '%' Name ';' +impl<'s> Composer<'s> for PEReference<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("%".as_bytes()).await?; + self.0.write(writer).await?; + writer.write_all(";".as_bytes()).await?; + Ok(()) + } +} + +/// [70] EntityDecl ::= GEDecl | PEDecl +impl<'s> Composer<'s> for EntityDecl<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + EntityDecl::GEDecl(ge_decl) => ge_decl.write(writer).await?, + EntityDecl::PEDecl(pe_decl) => pe_decl.write(writer).await?, + } + Ok(()) + } +} + +/// [71] GEDecl ::= '' +impl<'s> Composer<'s> for GEDecl<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("".as_bytes()).await?; + Ok(()) + } +} + +/// [72] PEDecl ::= '' +impl<'s> Composer<'s> for PEDecl<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("".as_bytes()).await?; + Ok(()) + } +} + +/// [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?) +impl<'s> Composer<'s> for EntityDef<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + EntityDef::EntityValue(entity_value) => entity_value.write(writer).await?, + EntityDef::ExternalID { + external_id, + n_data_decl, + } => { + external_id.write(writer).await?; + if let Some(n_data_decl) = n_data_decl { + n_data_decl.write(writer).await?; + } + } + } + Ok(()) + } +} + +/// [74] PEDef ::= EntityValue | ExternalID +impl<'s> Composer<'s> for PEDef<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + PEDef::EntityValue(entity_value) => entity_value.write(writer).await?, + PEDef::ExternalID(external_id) => external_id.write(writer).await?, + } + Ok(()) + } +} + +/// [75] ExternalID ::= 'SYSTEM' S SystemLiteral | 'PUBLIC' S PubidLiteral S SystemLiteral +impl<'s> Composer<'s> for ExternalID<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + match self { + ExternalID::SYSTEM { system_identifier } => { + writer.write_all("SYSTEM".as_bytes()).await?; + S.write(writer).await?; + system_identifier.write(writer).await?; + } + ExternalID::PUBLIC { + public_identifier, + system_identifier, + } => { + writer.write_all("PUBLIC".as_bytes()).await?; + S.write(writer).await?; + public_identifier.write(writer).await?; + S.write(writer).await?; + system_identifier.write(writer).await?; + } + } + Ok(()) + } +} + +/// [76] NDataDecl ::= S 'NDATA' S Name +impl<'s> Composer<'s> for NDataDecl<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + S.write(writer).await?; + writer.write_all("NDATA".as_bytes()).await?; + S.write(writer).await?; + self.0.write(writer).await?; + Ok(()) + } +} + +/// [77] TextDecl ::= '' +impl<'s> Composer<'s> for TextDecl<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("".as_bytes()).await?; + Ok(()) + } +} + +/// [78] extParsedEnt ::= TextDecl? content +impl<'s> Composer<'s> for ExtParsedEnt<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + if let Some(text_decl) = &self.text_decl { + text_decl.write(writer).await?; + } + self.content.write(writer).await?; + Ok(()) + } +} + +/// [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName +impl<'s> Composer<'s> for EncodingDecl<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + S.write(writer).await?; + writer.write_all("encoding".as_bytes()).await?; + Eq.write(writer).await?; + writer.write_all("\"".as_bytes()).await?; + self.0.write(writer).await?; + writer.write_all("\"".as_bytes()).await?; + Ok(()) + } +} + +/// [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* +impl<'s> Composer<'s> for EncName<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all(self.0.as_bytes()).await?; + Ok(()) + } +} + +/// [82] NotationDecl ::= '' +impl<'s> Composer<'s> for NotationDecl<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all(" external_id.write(writer).await?, + NotationDeclID::Public(public_id) => public_id.write(writer).await?, + } + writer.write_all(">".as_bytes()).await?; + Ok(()) + } +} + +/// [83] PublicID ::= 'PUBLIC' S PubidLiteral +impl<'s> Composer<'s> for PublicID<'s> { + async fn write(&self, writer: &mut W) -> io::Result<()> + where + W: Unpin + AsyncWrite, + { + writer.write_all("PUBLIC".as_bytes()).await?; + S.write(writer).await?; + self.0.write(writer).await?; + Ok(()) } } diff --git a/src/xml/mod.rs b/src/xml/mod.rs index 8df2f41..f072fde 100644 --- a/src/xml/mod.rs +++ b/src/xml/mod.rs @@ -345,6 +345,7 @@ pub struct Elementdecl<'s> { } // TODO: casings??? +// TODO: wtf does that todo mean? /// [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children #[derive(Clone, Debug)] pub enum Contentspec<'s> { @@ -469,7 +470,8 @@ pub struct Enumeration<'s>(Vec>); pub enum DefaultDecl<'s> { Required, Implied, - Fixed(AttValue<'s>), + /// if bool == true, attribute MUST always have default value + Fixed(bool, AttValue<'s>), } /// [61] conditionalSect ::= includeSect | ignoreSect @@ -544,7 +546,7 @@ pub enum EntityDef<'s> { EntityValue(EntityValue<'s>), ExternalID { external_id: ExternalID<'s>, - ndata_decl: Option>, + n_data_decl: Option>, }, } @@ -583,8 +585,9 @@ pub struct ExtParsedEnt<'s> { content: Content<'s>, } -/// [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName +/// [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' | "'" EncName "'" ) #[derive(Debug)] +// TODO?: select quote version pub struct EncodingDecl<'s>(EncName<'s>); /// [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* diff --git a/src/xml/parsers.rs b/src/xml/parsers.rs index 93ff5b1..232ebd0 100644 --- a/src/xml/parsers.rs +++ b/src/xml/parsers.rs @@ -1082,8 +1082,8 @@ impl<'s> Parser<'s, DefaultDecl<'s>> for DefaultDecl<'s> { value(DefaultDecl::Required, tag("#REQUIRED")), value(DefaultDecl::Implied, tag("#IMPLIED")), map( - preceded(opt(pair(tag("#FIXED"), S::parse)), AttValue::parse), - |att_value| DefaultDecl::Fixed(att_value), + pair(opt(pair(tag("#FIXED"), S::parse)), AttValue::parse), + |(must, att_value)| DefaultDecl::Fixed(must.is_some(), att_value), ), ))(input) } @@ -1272,9 +1272,9 @@ impl<'s> Parser<'s, EntityDef<'s>> for EntityDef<'s> { }), map( pair(ExternalID::parse, opt(NDataDecl::parse)), - |(external_id, ndata_decl)| EntityDef::ExternalID { + |(external_id, n_data_decl)| EntityDef::ExternalID { external_id, - ndata_decl, + n_data_decl, }, ), ))(input)