]> git.proxmox.com Git - rustc.git/blame - vendor/xml5ever/src/serialize/mod.rs
New upstream version 1.61.0+dfsg1
[rustc.git] / vendor / xml5ever / src / serialize / mod.rs
CommitLineData
3dfed10e
XL
1// Copyright 2014-2017 The html5ever Project Developers. See the
2// COPYRIGHT file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10pub use markup5ever::serialize::{AttrRef, Serialize, Serializer, TraversalScope};
11use std::io::{self, Write};
12use crate::tree_builder::NamespaceMap;
13use crate::QualName;
14
15#[derive(Clone)]
16/// Struct for setting serializer options.
17pub struct SerializeOpts {
18 /// Serialize the root node? Default: ChildrenOnly
19 pub traversal_scope: TraversalScope,
20}
21
22impl Default for SerializeOpts {
23 fn default() -> SerializeOpts {
24 SerializeOpts {
25 traversal_scope: TraversalScope::ChildrenOnly(None),
26 }
27 }
28}
29
30/// Method for serializing generic node to a given writer.
31pub fn serialize<Wr, T>(writer: Wr, node: &T, opts: SerializeOpts) -> io::Result<()>
32where
33 Wr: Write,
34 T: Serialize,
35{
36 let mut ser = XmlSerializer::new(writer);
37 node.serialize(&mut ser, opts.traversal_scope)
38}
39
40/// Struct used for serializing nodes into a text that other XML
41/// parses can read.
42///
43/// Serializer contains a set of functions (start_elem, end_elem...)
44/// that make parsing nodes easier.
45pub struct XmlSerializer<Wr> {
46 writer: Wr,
47 namespace_stack: NamespaceMapStack,
48}
49
50#[derive(Debug)]
51struct NamespaceMapStack(Vec<NamespaceMap>);
52
53impl NamespaceMapStack {
54 fn new() -> NamespaceMapStack {
55 NamespaceMapStack(vec![])
56 }
57
58 fn push(&mut self, namespace: NamespaceMap) {
59 self.0.push(namespace);
60 }
61
62 fn pop(&mut self) {
63 self.0.pop();
64 }
65}
66
67/// Writes given text into the Serializer, escaping it,
68/// depending on where the text is written inside the tag or attribute value.
69///
70/// For example
71///```text
72/// <tag>'&-quotes'</tag> becomes <tag>'&amp;-quotes'</tag>
73/// <tag = "'&-quotes'"> becomes <tag = "&apos;&amp;-quotes&apos;"
74///```
75fn write_to_buf_escaped<W: Write>(writer: &mut W, text: &str, attr_mode: bool) -> io::Result<()> {
76 for c in text.chars() {
77 match c {
78 '&' => writer.write_all(b"&amp;"),
79 '\'' if attr_mode => writer.write_all(b"&apos;"),
80 '"' if attr_mode => writer.write_all(b"&quot;"),
81 '<' if !attr_mode => writer.write_all(b"&lt;"),
82 '>' if !attr_mode => writer.write_all(b"&gt;"),
83 c => writer.write_fmt(format_args!("{}", c)),
84 }?;
85 }
86 Ok(())
87}
88
89#[inline]
90fn write_qual_name<W: Write>(writer: &mut W, name: &QualName) -> io::Result<()> {
91 if let Some(ref prefix) = name.prefix {
92 writer.write_all(&prefix.as_bytes())?;
93 writer.write_all(b":")?;
94 writer.write_all(&*name.local.as_bytes())?;
95 } else {
96 writer.write_all(&*name.local.as_bytes())?;
97 }
98
99 Ok(())
100}
101
102impl<Wr: Write> XmlSerializer<Wr> {
103 /// Creates a new Serializier from a writer and given serialization options.
104 pub fn new(writer: Wr) -> Self {
105 XmlSerializer {
106 writer: writer,
107 namespace_stack: NamespaceMapStack::new(),
108 }
109 }
110
111 #[inline(always)]
112 fn qual_name(&mut self, name: &QualName) -> io::Result<()> {
113 self.find_or_insert_ns(name);
114 write_qual_name(&mut self.writer, name)
115 }
116
117 #[inline(always)]
118 fn qual_attr_name(&mut self, name: &QualName) -> io::Result<()> {
119 self.find_or_insert_ns(name);
120 write_qual_name(&mut self.writer, name)
121 }
122
123 fn find_uri(&self, name: &QualName) -> bool {
124 let mut found = false;
125 for stack in self.namespace_stack.0.iter().rev() {
126 if let Some(&Some(ref el)) = stack.get(&name.prefix) {
127 found = *el == name.ns;
128 break;
129 }
130 }
131 found
132 }
133
134 fn find_or_insert_ns(&mut self, name: &QualName) {
135 if name.prefix.is_some() || &*name.ns != "" {
136 if !self.find_uri(name) {
137 if let Some(last_ns) = self.namespace_stack.0.last_mut() {
138 last_ns.insert(name);
139 }
140 }
141 }
142 }
143}
144
145impl<Wr: Write> Serializer for XmlSerializer<Wr> {
146 /// Serializes given start element into text. Start element contains
147 /// qualified name and an attributes iterator.
148 fn start_elem<'a, AttrIter>(&mut self, name: QualName, attrs: AttrIter) -> io::Result<()>
149 where
150 AttrIter: Iterator<Item = AttrRef<'a>>,
151 {
152 self.namespace_stack.push(NamespaceMap::empty());
153
154 self.writer.write_all(b"<")?;
155 self.qual_name(&name)?;
156 if let Some(current_namespace) = self.namespace_stack.0.last() {
157 for (prefix, url_opt) in current_namespace.get_scope_iter() {
158 self.writer.write_all(b" xmlns")?;
159 if let &Some(ref p) = prefix {
160 self.writer.write_all(b":")?;
161 self.writer.write_all(&*p.as_bytes())?;
162 }
163
164 self.writer.write_all(b"=\"")?;
165 let url = if let &Some(ref a) = url_opt {
166 a.as_bytes()
167 } else {
168 b""
169 };
170 self.writer.write_all(url)?;
171 self.writer.write_all(b"\"")?;
172 }
173 }
174 for (name, value) in attrs {
175 self.writer.write_all(b" ")?;
176 self.qual_attr_name(&name)?;
177 self.writer.write_all(b"=\"")?;
178 write_to_buf_escaped(&mut self.writer, value, true)?;
179 self.writer.write_all(b"\"")?;
180 }
181 self.writer.write_all(b">")?;
182 Ok(())
183 }
184
185 /// Serializes given end element into text.
186 fn end_elem(&mut self, name: QualName) -> io::Result<()> {
187 self.namespace_stack.pop();
188 self.writer.write_all(b"</")?;
189 self.qual_name(&name)?;
190 self.writer.write_all(b">")
191 }
192
193 /// Serializes comment into text.
194 fn write_comment(&mut self, text: &str) -> io::Result<()> {
195 self.writer.write_all(b"<!--")?;
196 self.writer.write_all(text.as_bytes())?;
197 self.writer.write_all(b"-->")
198 }
199
200 /// Serializes given doctype
201 fn write_doctype(&mut self, name: &str) -> io::Result<()> {
202 self.writer.write_all(b"<!DOCTYPE ")?;
203 self.writer.write_all(name.as_bytes())?;
204 self.writer.write_all(b">")
205 }
206
207 /// Serializes text for a node or an attributes.
208 fn write_text(&mut self, text: &str) -> io::Result<()> {
209 write_to_buf_escaped(&mut self.writer, text, false)
210 }
211
212 /// Serializes given processing instruction.
213 fn write_processing_instruction(&mut self, target: &str, data: &str) -> io::Result<()> {
214 self.writer.write_all(b"<?")?;
215 self.writer.write_all(target.as_bytes())?;
216 self.writer.write_all(b" ")?;
217 self.writer.write_all(data.as_bytes())?;
218 self.writer.write_all(b"?>")
219 }
220}