1use crate::document::Paragraph;
4use crate::error::Result;
5use crate::xml::{RawXmlElement, RawXmlNode};
6use quick_xml::events::{BytesEnd, BytesStart, Event};
7use quick_xml::{Reader, Writer};
8use std::io::BufRead;
9
10#[derive(Clone, Debug, Default)]
12pub struct Table {
13 pub properties: Option<RawXmlNode>,
15 pub grid: Vec<GridColumn>,
17 pub rows: Vec<TableRow>,
19 pub unknown_children: Vec<RawXmlNode>,
21}
22
23#[derive(Clone, Debug, Default)]
25pub struct GridColumn {
26 pub width: Option<i32>,
28}
29
30#[derive(Clone, Debug, Default)]
32pub struct TableRow {
33 pub properties: Option<RawXmlNode>,
35 pub cells: Vec<TableCell>,
37 pub unknown_children: Vec<RawXmlNode>,
39}
40
41#[derive(Clone, Debug, Default)]
43pub struct TableCell {
44 pub properties: Option<TableCellProperties>,
46 pub paragraphs: Vec<Paragraph>,
48 pub unknown_children: Vec<RawXmlNode>,
50}
51
52#[derive(Clone, Debug, Default)]
54pub struct TableCellProperties {
55 pub width: Option<i32>,
57 pub grid_span: Option<u32>,
59 pub v_merge: Option<VMerge>,
61 pub v_align: Option<String>,
63 pub unknown_children: Vec<RawXmlNode>,
65}
66
67#[derive(Clone, Debug)]
69pub enum VMerge {
70 Restart,
71 Continue,
72}
73
74impl Table {
75 pub fn new(rows: usize, cols: usize) -> Self {
77 let mut table_rows = Vec::with_capacity(rows);
78 for _ in 0..rows {
79 let mut cells = Vec::with_capacity(cols);
80 for _ in 0..cols {
81 cells.push(TableCell::new(""));
82 }
83 table_rows.push(TableRow {
84 cells,
85 ..Default::default()
86 });
87 }
88
89 let grid = (0..cols).map(|_| GridColumn { width: None }).collect();
90
91 Table {
92 grid,
93 rows: table_rows,
94 ..Default::default()
95 }
96 }
97
98 pub fn from_data<S: Into<String> + Clone>(data: &[&[S]]) -> Self {
100 let rows: Vec<TableRow> = data
101 .iter()
102 .map(|row| {
103 let cells: Vec<TableCell> = row
104 .iter()
105 .map(|text| TableCell::new(text.clone()))
106 .collect();
107 TableRow {
108 cells,
109 ..Default::default()
110 }
111 })
112 .collect();
113
114 let cols = data.first().map(|r| r.len()).unwrap_or(0);
115 let grid = (0..cols).map(|_| GridColumn { width: None }).collect();
116
117 Table {
118 grid,
119 rows,
120 ..Default::default()
121 }
122 }
123
124 pub fn from_reader<R: BufRead>(reader: &mut Reader<R>, _start: &BytesStart) -> Result<Self> {
126 let mut table = Table::default();
127 let mut buf = Vec::new();
128
129 loop {
130 match reader.read_event_into(&mut buf)? {
131 Event::Start(e) => {
132 let local = e.name().local_name();
133
134 match local.as_ref() {
135 b"tblPr" => {
136 let raw = RawXmlElement::from_reader(reader, &e)?;
137 table.properties = Some(RawXmlNode::Element(raw));
138 }
139 b"tblGrid" => {
140 table.grid = parse_table_grid(reader)?;
141 }
142 b"tr" => {
143 let row = TableRow::from_reader(reader, &e)?;
144 table.rows.push(row);
145 }
146 _ => {
147 let raw = RawXmlElement::from_reader(reader, &e)?;
148 table.unknown_children.push(RawXmlNode::Element(raw));
149 }
150 }
151 }
152 Event::Empty(e) => {
153 let raw = RawXmlElement {
155 name: String::from_utf8_lossy(e.name().as_ref()).to_string(),
156 attributes: e
157 .attributes()
158 .filter_map(|a| a.ok())
159 .map(|a| {
160 (
161 String::from_utf8_lossy(a.key.as_ref()).to_string(),
162 String::from_utf8_lossy(&a.value).to_string(),
163 )
164 })
165 .collect(),
166 children: Vec::new(),
167 self_closing: true,
168 };
169 table.unknown_children.push(RawXmlNode::Element(raw));
170 }
171 Event::End(e) => {
172 if e.name().local_name().as_ref() == b"tbl" {
173 break;
174 }
175 }
176 Event::Eof => break,
177 _ => {}
178 }
179 buf.clear();
180 }
181
182 Ok(table)
183 }
184
185 pub fn row_count(&self) -> usize {
187 self.rows.len()
188 }
189
190 pub fn column_count(&self) -> usize {
192 self.rows.first().map(|r| r.cells.len()).unwrap_or(0)
193 }
194
195 pub fn cell(&self, row: usize, col: usize) -> Option<&TableCell> {
197 self.rows.get(row)?.cells.get(col)
198 }
199
200 pub fn rows(&self) -> impl Iterator<Item = &TableRow> {
202 self.rows.iter()
203 }
204
205 pub fn cell_mut(&mut self, row: usize, col: usize) -> Option<&mut TableCell> {
207 self.rows.get_mut(row)?.cells.get_mut(col)
208 }
209
210 pub fn row_mut(&mut self, index: usize) -> Option<&mut TableRow> {
212 self.rows.get_mut(index)
213 }
214
215 pub fn add_row(&mut self, row: TableRow) {
217 self.rows.push(row);
218 }
219
220 pub fn set_cell_text(&mut self, row: usize, col: usize, text: impl Into<String>) {
222 if let Some(cell) = self.cell_mut(row, col) {
223 cell.set_text(text);
224 }
225 }
226
227 pub fn set_column_width(&mut self, col: usize, width: i32) {
229 if col < self.grid.len() {
230 self.grid[col].width = Some(width);
231 }
232 }
233
234 pub fn write_to<W: std::io::Write>(&self, writer: &mut Writer<W>) -> Result<()> {
236 writer.write_event(Event::Start(BytesStart::new("w:tbl")))?;
237
238 if let Some(props) = &self.properties {
240 props.write_to(writer)?;
241 }
242
243 if !self.grid.is_empty() {
245 writer.write_event(Event::Start(BytesStart::new("w:tblGrid")))?;
246 for col in &self.grid {
247 let mut elem = BytesStart::new("w:gridCol");
248 if let Some(w) = col.width {
249 elem.push_attribute(("w:w", w.to_string().as_str()));
250 }
251 writer.write_event(Event::Empty(elem))?;
252 }
253 writer.write_event(Event::End(BytesEnd::new("w:tblGrid")))?;
254 }
255
256 for row in &self.rows {
258 row.write_to(writer)?;
259 }
260
261 for child in &self.unknown_children {
263 child.write_to(writer)?;
264 }
265
266 writer.write_event(Event::End(BytesEnd::new("w:tbl")))?;
267 Ok(())
268 }
269}
270
271impl TableRow {
272 pub fn new(cell_count: usize) -> Self {
274 let cells = (0..cell_count).map(|_| TableCell::new("")).collect();
275 TableRow {
276 cells,
277 ..Default::default()
278 }
279 }
280
281 pub fn from_texts<S: Into<String>>(texts: impl IntoIterator<Item = S>) -> Self {
283 let cells = texts.into_iter().map(TableCell::new).collect();
284 TableRow {
285 cells,
286 ..Default::default()
287 }
288 }
289
290 pub fn from_reader<R: BufRead>(reader: &mut Reader<R>, _start: &BytesStart) -> Result<Self> {
292 let mut row = TableRow::default();
293 let mut buf = Vec::new();
294
295 loop {
296 match reader.read_event_into(&mut buf)? {
297 Event::Start(e) => {
298 let local = e.name().local_name();
299
300 match local.as_ref() {
301 b"trPr" => {
302 let raw = RawXmlElement::from_reader(reader, &e)?;
303 row.properties = Some(RawXmlNode::Element(raw));
304 }
305 b"tc" => {
306 let cell = TableCell::from_reader(reader, &e)?;
307 row.cells.push(cell);
308 }
309 _ => {
310 let raw = RawXmlElement::from_reader(reader, &e)?;
311 row.unknown_children.push(RawXmlNode::Element(raw));
312 }
313 }
314 }
315 Event::Empty(e) => {
316 let raw = RawXmlElement {
317 name: String::from_utf8_lossy(e.name().as_ref()).to_string(),
318 attributes: e
319 .attributes()
320 .filter_map(|a| a.ok())
321 .map(|a| {
322 (
323 String::from_utf8_lossy(a.key.as_ref()).to_string(),
324 String::from_utf8_lossy(&a.value).to_string(),
325 )
326 })
327 .collect(),
328 children: Vec::new(),
329 self_closing: true,
330 };
331 row.unknown_children.push(RawXmlNode::Element(raw));
332 }
333 Event::End(e) => {
334 if e.name().local_name().as_ref() == b"tr" {
335 break;
336 }
337 }
338 Event::Eof => break,
339 _ => {}
340 }
341 buf.clear();
342 }
343
344 Ok(row)
345 }
346
347 pub fn cell_count(&self) -> usize {
349 self.cells.len()
350 }
351
352 pub fn cells(&self) -> impl Iterator<Item = &TableCell> {
354 self.cells.iter()
355 }
356
357 pub fn cell_mut(&mut self, index: usize) -> Option<&mut TableCell> {
359 self.cells.get_mut(index)
360 }
361
362 pub fn add_cell(&mut self, cell: TableCell) {
364 self.cells.push(cell);
365 }
366
367 pub fn write_to<W: std::io::Write>(&self, writer: &mut Writer<W>) -> Result<()> {
369 writer.write_event(Event::Start(BytesStart::new("w:tr")))?;
370
371 if let Some(props) = &self.properties {
373 props.write_to(writer)?;
374 }
375
376 for cell in &self.cells {
378 cell.write_to(writer)?;
379 }
380
381 for child in &self.unknown_children {
383 child.write_to(writer)?;
384 }
385
386 writer.write_event(Event::End(BytesEnd::new("w:tr")))?;
387 Ok(())
388 }
389}
390
391impl TableCell {
392 pub fn new(text: impl Into<String>) -> Self {
394 let text = text.into();
395 let paragraphs = if text.is_empty() {
396 vec![Paragraph::default()]
397 } else {
398 vec![Paragraph::new(text)]
399 };
400 TableCell {
401 paragraphs,
402 ..Default::default()
403 }
404 }
405
406 pub fn set_text(&mut self, text: impl Into<String>) {
408 self.paragraphs.clear();
409 self.paragraphs.push(Paragraph::new(text));
410 }
411
412 pub fn add_paragraph(&mut self, para: Paragraph) {
414 self.paragraphs.push(para);
415 }
416
417 pub fn set_width(&mut self, width: i32) {
419 self.properties.get_or_insert_with(Default::default).width = Some(width);
420 }
421
422 pub fn set_grid_span(&mut self, span: u32) {
424 self.properties
425 .get_or_insert_with(Default::default)
426 .grid_span = Some(span);
427 }
428
429 pub fn set_v_merge(&mut self, v_merge: VMerge) {
431 self.properties.get_or_insert_with(Default::default).v_merge = Some(v_merge);
432 }
433
434 pub fn set_v_align(&mut self, align: impl Into<String>) {
436 self.properties.get_or_insert_with(Default::default).v_align = Some(align.into());
437 }
438
439 pub fn from_reader<R: BufRead>(reader: &mut Reader<R>, _start: &BytesStart) -> Result<Self> {
441 let mut cell = TableCell::default();
442 let mut buf = Vec::new();
443
444 loop {
445 match reader.read_event_into(&mut buf)? {
446 Event::Start(e) => {
447 let local = e.name().local_name();
448
449 match local.as_ref() {
450 b"tcPr" => {
451 cell.properties = Some(TableCellProperties::from_reader(reader)?);
452 }
453 b"p" => {
454 let para = Paragraph::from_reader(reader, &e)?;
455 cell.paragraphs.push(para);
456 }
457 _ => {
458 let raw = RawXmlElement::from_reader(reader, &e)?;
459 cell.unknown_children.push(RawXmlNode::Element(raw));
460 }
461 }
462 }
463 Event::Empty(e) => {
464 let local = e.name().local_name();
465 if local.as_ref() == b"p" {
466 let para = Paragraph::from_empty(&e)?;
467 cell.paragraphs.push(para);
468 } else {
469 let raw = RawXmlElement {
470 name: String::from_utf8_lossy(e.name().as_ref()).to_string(),
471 attributes: e
472 .attributes()
473 .filter_map(|a| a.ok())
474 .map(|a| {
475 (
476 String::from_utf8_lossy(a.key.as_ref()).to_string(),
477 String::from_utf8_lossy(&a.value).to_string(),
478 )
479 })
480 .collect(),
481 children: Vec::new(),
482 self_closing: true,
483 };
484 cell.unknown_children.push(RawXmlNode::Element(raw));
485 }
486 }
487 Event::End(e) => {
488 if e.name().local_name().as_ref() == b"tc" {
489 break;
490 }
491 }
492 Event::Eof => break,
493 _ => {}
494 }
495 buf.clear();
496 }
497
498 Ok(cell)
499 }
500
501 pub fn text(&self) -> String {
503 self.paragraphs
504 .iter()
505 .map(|p| p.text())
506 .collect::<Vec<_>>()
507 .join("\n")
508 }
509
510 pub fn paragraphs(&self) -> impl Iterator<Item = &Paragraph> {
512 self.paragraphs.iter()
513 }
514
515 pub fn write_to<W: std::io::Write>(&self, writer: &mut Writer<W>) -> Result<()> {
517 writer.write_event(Event::Start(BytesStart::new("w:tc")))?;
518
519 if let Some(props) = &self.properties {
521 props.write_to(writer)?;
522 }
523
524 if self.paragraphs.is_empty() {
526 writer.write_event(Event::Empty(BytesStart::new("w:p")))?;
528 } else {
529 for para in &self.paragraphs {
530 para.write_to(writer)?;
531 }
532 }
533
534 for child in &self.unknown_children {
536 child.write_to(writer)?;
537 }
538
539 writer.write_event(Event::End(BytesEnd::new("w:tc")))?;
540 Ok(())
541 }
542}
543
544impl TableCellProperties {
545 pub fn from_reader<R: BufRead>(reader: &mut Reader<R>) -> Result<Self> {
547 let mut props = TableCellProperties::default();
548 let mut buf = Vec::new();
549
550 loop {
551 match reader.read_event_into(&mut buf)? {
552 Event::Start(e) => {
553 let raw = RawXmlElement::from_reader(reader, &e)?;
554 props.unknown_children.push(RawXmlNode::Element(raw));
555 }
556 Event::Empty(e) => {
557 let local = e.name().local_name();
558
559 match local.as_ref() {
560 b"tcW" => {
561 props.width = crate::xml::get_attr(&e, "w:w")
562 .or_else(|| crate::xml::get_attr(&e, "w"))
563 .and_then(|v| v.parse().ok());
564 }
565 b"gridSpan" => {
566 props.grid_span =
567 crate::xml::get_w_val(&e).and_then(|v| v.parse().ok());
568 }
569 b"vMerge" => {
570 let val = crate::xml::get_w_val(&e);
571 props.v_merge = Some(match val.as_deref() {
572 Some("restart") => VMerge::Restart,
573 _ => VMerge::Continue,
574 });
575 }
576 b"vAlign" => {
577 props.v_align = crate::xml::get_w_val(&e);
578 }
579 _ => {
580 let raw = RawXmlElement {
581 name: String::from_utf8_lossy(e.name().as_ref()).to_string(),
582 attributes: e
583 .attributes()
584 .filter_map(|a| a.ok())
585 .map(|a| {
586 (
587 String::from_utf8_lossy(a.key.as_ref()).to_string(),
588 String::from_utf8_lossy(&a.value).to_string(),
589 )
590 })
591 .collect(),
592 children: Vec::new(),
593 self_closing: true,
594 };
595 props.unknown_children.push(RawXmlNode::Element(raw));
596 }
597 }
598 }
599 Event::End(e) => {
600 if e.name().local_name().as_ref() == b"tcPr" {
601 break;
602 }
603 }
604 Event::Eof => break,
605 _ => {}
606 }
607 buf.clear();
608 }
609
610 Ok(props)
611 }
612
613 pub fn write_to<W: std::io::Write>(&self, writer: &mut Writer<W>) -> Result<()> {
615 let has_content = self.width.is_some()
616 || self.grid_span.is_some()
617 || self.v_merge.is_some()
618 || self.v_align.is_some()
619 || !self.unknown_children.is_empty();
620
621 if !has_content {
622 return Ok(());
623 }
624
625 writer.write_event(Event::Start(BytesStart::new("w:tcPr")))?;
626
627 if let Some(width) = self.width {
629 let mut elem = BytesStart::new("w:tcW");
630 elem.push_attribute(("w:w", width.to_string().as_str()));
631 elem.push_attribute(("w:type", "dxa"));
632 writer.write_event(Event::Empty(elem))?;
633 }
634
635 if let Some(span) = self.grid_span {
637 let mut elem = BytesStart::new("w:gridSpan");
638 elem.push_attribute(("w:val", span.to_string().as_str()));
639 writer.write_event(Event::Empty(elem))?;
640 }
641
642 if let Some(v_merge) = &self.v_merge {
644 let mut elem = BytesStart::new("w:vMerge");
645 match v_merge {
646 VMerge::Restart => elem.push_attribute(("w:val", "restart")),
647 VMerge::Continue => {}
648 }
649 writer.write_event(Event::Empty(elem))?;
650 }
651
652 if let Some(v_align) = &self.v_align {
654 let mut elem = BytesStart::new("w:vAlign");
655 elem.push_attribute(("w:val", v_align.as_str()));
656 writer.write_event(Event::Empty(elem))?;
657 }
658
659 for child in &self.unknown_children {
661 child.write_to(writer)?;
662 }
663
664 writer.write_event(Event::End(BytesEnd::new("w:tcPr")))?;
665 Ok(())
666 }
667}
668
669fn parse_table_grid<R: BufRead>(reader: &mut Reader<R>) -> Result<Vec<GridColumn>> {
671 let mut columns = Vec::new();
672 let mut buf = Vec::new();
673
674 loop {
675 match reader.read_event_into(&mut buf)? {
676 Event::Empty(e) => {
677 if e.name().local_name().as_ref() == b"gridCol" {
678 let width = crate::xml::get_attr(&e, "w:w")
679 .or_else(|| crate::xml::get_attr(&e, "w"))
680 .and_then(|v| v.parse().ok());
681 columns.push(GridColumn { width });
682 }
683 }
684 Event::End(e) => {
685 if e.name().local_name().as_ref() == b"tblGrid" {
686 break;
687 }
688 }
689 Event::Eof => break,
690 _ => {}
691 }
692 buf.clear();
693 }
694
695 Ok(columns)
696}