Skip to content

Commit 703d141

Browse files
committed
Add SerializeOpts flag for creating missing parent ElemInfo
1 parent 1c3b7a4 commit 703d141

File tree

2 files changed

+31
-8
lines changed

2 files changed

+31
-8
lines changed

html5ever/src/serialize/mod.rs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,21 @@ pub struct SerializeOpts {
2626

2727
/// Serialize the root node? Default: ChildrenOnly
2828
pub traversal_scope: TraversalScope,
29+
30+
/// If the serializer is asked to serialize an invalid tree, the default
31+
/// behavior is to panic in the event that an `end_elem` is created without a
32+
/// matching `start_elem`. Setting this to true will prevent those panics by
33+
/// creating a default parent on the element stack. No extra start elem will
34+
/// actually be written. Default: false
35+
pub create_missing_parent: bool,
2936
}
3037

3138
impl Default for SerializeOpts {
3239
fn default() -> SerializeOpts {
3340
SerializeOpts {
3441
scripting_enabled: true,
3542
traversal_scope: TraversalScope::ChildrenOnly,
43+
create_missing_parent: false,
3644
}
3745
}
3846
}
@@ -73,8 +81,12 @@ impl<Wr: Write> HtmlSerializer<Wr> {
7381

7482
fn parent(&mut self) -> &mut ElemInfo {
7583
if self.stack.len() == 0 {
76-
warn!("ElemInfo stack empty, creating new parent");
77-
self.stack.push(Default::default());
84+
if self.opts.create_missing_parent {
85+
warn!("ElemInfo stack empty, creating new parent");
86+
self.stack.push(Default::default());
87+
} else {
88+
panic!("no parent ElemInfo")
89+
}
7890
}
7991
self.stack.last_mut().unwrap()
8092
}
@@ -160,10 +172,14 @@ impl<Wr: Write> Serializer for HtmlSerializer<Wr> {
160172
}
161173

162174
fn end_elem(&mut self, name: QualName) -> io::Result<()> {
163-
let info = self.stack.pop().unwrap_or_else(|| {
164-
warn!("missing ElemInfo, creating default.");
165-
Default::default()
166-
});
175+
let info = match self.stack.pop() {
176+
Some(info) => info,
177+
None if self.opts.create_missing_parent => {
178+
warn!("missing ElemInfo, creating default.");
179+
Default::default()
180+
}
181+
_ => panic!("no ElemInfo"),
182+
};
167183
if info.ignore_children {
168184
return Ok(());
169185
}

html5ever/tests/serializer.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use html5ever::driver::ParseOpts;
1616
use html5ever::rcdom::RcDom;
1717
use html5ever::tendril::{StrTendril, SliceExt, TendrilSink};
1818
use html5ever::tokenizer::{Token, TokenSink, TokenSinkResult, TagKind, Tokenizer};
19-
use html5ever::serialize::{Serialize, Serializer, TraversalScope};
19+
use html5ever::serialize::{Serialize, Serializer, TraversalScope, SerializeOpts};
2020

2121
use std::io;
2222

@@ -83,7 +83,14 @@ fn tokenize_and_serialize(input: StrTendril) -> StrTendril {
8383
tokenizer.feed(&mut input);
8484
tokenizer.end();
8585
let mut output = ::std::io::Cursor::new(vec![]);
86-
serialize(&mut output, &tokenizer.sink, Default::default()).unwrap();
86+
serialize(
87+
&mut output,
88+
&tokenizer.sink,
89+
SerializeOpts {
90+
create_missing_parent: true,
91+
..Default::default()
92+
},
93+
).unwrap();
8794
StrTendril::try_from_byte_slice(&output.into_inner()).unwrap()
8895
}
8996

0 commit comments

Comments
 (0)