1use crate::{
4 attribute::AttributeValue,
5 parse::Parse,
6 prolog::subset::entity::{entity_value::EntityValue, EntitySource},
7 transcode::Decode,
8 Document, IResult, Name,
9};
10use nom::{
11 branch::alt,
12 bytes::complete::tag,
13 character::complete::{char, digit1, hex_digit1},
14 combinator::map,
15 sequence::tuple,
16};
17use std::{cell::RefCell, collections::HashMap, rc::Rc};
18
19#[derive(Clone, PartialEq, Eq)]
20pub enum Reference {
21 EntityRef(Name),
22 CharRef(String),
23}
24
25impl<'a> Parse<'a> for Reference {
26 type Args = EntitySource;
27 type Output = IResult<&'a str, Self>;
29 fn parse(input: &'a str, args: Self::Args) -> Self::Output {
31 alt((
32 move |i| Self::parse_entity_ref(i, args.clone()),
33 Self::parse_char_reference,
34 ))(input)
35 }
36}
37impl Reference {
38 pub(crate) fn normalize_entity(
39 &self,
40 entity_references: Rc<RefCell<HashMap<(Name, EntitySource), EntityValue>>>,
41 ) -> EntityValue {
42 match self {
43 Reference::EntityRef(name) => {
44 let refs_map = entity_references.borrow();
45
46 let possible_sources = [EntitySource::External, EntitySource::Internal];
48 let entity_value = possible_sources
49 .iter()
50 .filter_map(|source| refs_map.get(&(name.clone(), source.clone())).cloned())
51 .next()
52 .unwrap_or_else(|| EntityValue::Value(name.local_part.clone())); match entity_value {
55 EntityValue::Value(val) => {
56 if refs_map.contains_key(&(
57 Name {
58 prefix: None,
59 local_part: val.clone(),
60 },
61 EntitySource::Internal,
62 )) {
63 let reference_name = Name {
65 prefix: None,
66 local_part: val,
67 };
68 Reference::EntityRef(reference_name)
69 .normalize_entity(entity_references.clone())
70 } else {
71 EntityValue::Value(val)
72 }
73 }
74 EntityValue::Reference(ref next_ref) => {
75 next_ref.normalize_entity(entity_references.clone())
77 }
78 _ => entity_value,
79 }
80 }
81 Reference::CharRef(value) => EntityValue::Value(value.clone()),
82 }
83 }
84
85 pub(crate) fn normalize_attribute(
86 &self,
87 entity_references: Rc<RefCell<HashMap<(Name, EntitySource), EntityValue>>>,
88 entity_source: EntitySource,
89 ) -> AttributeValue {
90 match self {
91 Reference::EntityRef(name) => {
92 let refs_map = entity_references.borrow();
93 match refs_map
94 .get(&(name.clone(), entity_source.clone()))
95 .cloned()
96 {
97 Some(EntityValue::Value(val))
98 if refs_map.contains_key(&(
99 Name {
100 prefix: None,
101 local_part: val.clone(),
102 },
103 entity_source.clone(),
104 )) =>
105 {
106 let reference_name = Name {
107 prefix: None,
108 local_part: val,
109 };
110 Reference::EntityRef(reference_name)
111 .normalize_attribute(entity_references.clone(), entity_source.clone())
112 }
113 Some(EntityValue::Reference(Reference::EntityRef(entity))) => {
114 if let Some(EntityValue::Value(val)) = refs_map
115 .get(&(entity.clone(), EntitySource::Internal))
116 .cloned()
117 {
118 AttributeValue::Value(val)
119 } else {
120 Reference::EntityRef(entity.clone()).normalize_attribute(
121 entity_references.clone(),
122 EntitySource::External,
123 )
124 }
125 }
126 Some(entity_value) => {
127 match entity_value {
129 EntityValue::Value(val) => AttributeValue::Value(val),
130 EntityValue::Reference(reference) => reference.normalize_attribute(
131 entity_references.clone(),
132 entity_source.clone(),
133 ),
134 EntityValue::Document(doc) => {
135 if let Document::Empty = doc {
136 AttributeValue::EmptyExternalReference
137 } else {
138 unimplemented!(
139 "Unexpected Document variant to convert to AttributeValue"
140 )
141 }
142 }
143 _ => panic!("Unexpected EntityValue variant"),
144 }
145 }
146 None => {
147 if entity_source == EntitySource::External {
148 if let Reference::EntityRef(_name) = &self {
149 AttributeValue::Reference(self.clone())
150 } else {
151 AttributeValue::Value(name.local_part.clone())
152 }
153 } else {
154 AttributeValue::Value(name.local_part.clone())
155 }
156 }
157 }
158 }
159 Reference::CharRef(value) => AttributeValue::Value(value.clone()),
160 }
161 }
162}
163
164impl<'a> ParseReference<'a> for Reference {}
165impl Decode for Reference {
166 fn as_str(&self) -> &str {
167 match self {
168 Reference::EntityRef(name) => &name.local_part,
169 Reference::CharRef(value) => value,
170 }
171 }
172}
173
174pub trait ParseReference<'a>: Parse<'a> + Decode {
175 fn parse_entity_ref(input: &str, _entity_source: EntitySource) -> IResult<&str, Reference> {
177 let (input, reference) = map(
178 tuple((char('&'), Self::parse_name, char(';'))),
179 |(_, name, _)| Reference::EntityRef(name),
180 )(input)?;
181 Ok((input, reference))
182 }
183
184 fn parse_parameter_reference(input: &str) -> IResult<&str, Reference> {
186 let (input, output) = map(
187 tuple((char('%'), Self::parse_name, char(';'))),
188 |(_, name, _)| Reference::EntityRef(name),
189 )(input)?;
190 Ok((input, output))
191 }
192
193 fn parse_char_reference(input: &str) -> IResult<&str, Reference> {
195 alt((
197 map(
198 tuple((tag("&#"), digit1, tag(";"))),
199 |(start, digits, end): (&str, &str, &str)| {
200 let reconstructed = format!("{}{}{}", start, digits, end);
201 let decoded = reconstructed.decode().unwrap().into_owned();
202 Reference::CharRef(decoded)
203 },
204 ),
205 map(
206 tuple((tag("&#x"), hex_digit1, tag(";"))),
207 |(start, hex, end): (&str, &str, &str)| {
208 let reconstructed = format!("{}{}{}", start, hex, end);
209 let decoded = reconstructed.decode().unwrap().into_owned();
210 Reference::CharRef(decoded)
211 },
212 ),
213 ))(input)
214 }
215}