dm2xcod 0.3.14

DOCX to Markdown converter written in Rust
Documentation
use super::AstExtractor;
use crate::converter::{ConversionContext, ParagraphConverter, RunConverter, TableConverter};
use crate::core::ast::{BlockNode, DocumentAst};
use crate::render::escape_html_attr;
use crate::Result;
use rs_docx::document::{BodyContent, TableCell, TableCellContent};

#[derive(Debug, Default, Clone, Copy)]
pub struct DocxExtractor;

impl AstExtractor for DocxExtractor {
    fn extract<'a>(
        &self,
        body: &[BodyContent<'a>],
        context: &mut ConversionContext<'a>,
    ) -> Result<DocumentAst> {
        let mut doc = DocumentAst::default();
        for content in body {
            self.extract_content(content, context, &mut doc)?;
        }
        Ok(doc)
    }
}

impl DocxExtractor {
    fn extract_table_cell<'a>(
        &self,
        cell: &TableCell<'a>,
        context: &mut ConversionContext<'a>,
        output: &mut DocumentAst,
    ) -> Result<()> {
        for item in &cell.content {
            match item {
                TableCellContent::Paragraph(para) => {
                    let converted = ParagraphConverter::convert(para, context)?;
                    if !converted.is_empty() {
                        output.blocks.push(BlockNode::Paragraph(converted));
                    }
                }
                TableCellContent::Table(table) => {
                    let converted = TableConverter::convert(table, context)?;
                    output.blocks.push(BlockNode::TableHtml(converted));
                }
            }
        }
        Ok(())
    }

    fn extract_content<'a>(
        &self,
        content: &BodyContent<'a>,
        context: &mut ConversionContext<'a>,
        output: &mut DocumentAst,
    ) -> Result<()> {
        match content {
            BodyContent::Paragraph(para) => {
                let converted = ParagraphConverter::convert(para, context)?;
                if !converted.is_empty() {
                    output.blocks.push(BlockNode::Paragraph(converted));
                }
            }
            BodyContent::Table(table) => {
                let converted = TableConverter::convert(table, context)?;
                output.blocks.push(BlockNode::TableHtml(converted));
            }
            BodyContent::Run(run) => {
                let converted = RunConverter::convert(run, context, None)?;
                if !converted.is_empty() {
                    output.blocks.push(BlockNode::Paragraph(converted));
                }
            }
            BodyContent::TableCell(cell) => {
                self.extract_table_cell(cell, context, output)?;
            }
            BodyContent::Sdt(sdt) => {
                if let Some(sdt_content) = &sdt.content {
                    for child in &sdt_content.content {
                        self.extract_content(child, context, output)?;
                    }
                }
            }
            BodyContent::BookmarkStart(bookmark) => {
                if let Some(name) = &bookmark.name {
                    output.blocks.push(BlockNode::RawHtml(format!(
                        "<a id=\"{}\"></a>",
                        escape_html_attr(name)
                    )));
                }
            }
            BodyContent::BookmarkEnd(_) => {}
            _ => {}
        }
        Ok(())
    }
}