spsheet 0.1.0

A xlsx or ods read and write spreadsheet library
Documentation
//! Office Open XML xlsx read and write
extern crate chrono;
extern crate quick_xml;
extern crate time;
extern crate tempdir;
extern crate walkdir;
extern crate zip;

use file_common::*;
use std::collections::HashMap;
use std::io;
use std::path::Path;
use std::result;
use std::fs::File;
use std::string::FromUtf8Error;
use self::chrono::prelude::*;
use self::tempdir::TempDir;
use super::{Book,Sheet,Cell,Value,Style,column_and_row_to_index,index_to_column};

mod read_sheet;
mod read_shared_strings;
mod read_styles;
mod read_workbook_xml_rels;
mod read_workbook;
mod write_sheet;
mod write_shared_strings;
mod write_styles;
mod write_workbook;
mod write_workbook_xml_rels;

const CONTENT_TYPE_XML: &'static str = r#"<?xml version="1.0" encoding="UTF-8"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Override PartName="/_rels/.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/><Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/><Override PartName="/xl/_rels/workbook.xml.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Override PartName="/xl/worksheets/sheet4.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/worksheets/sheet3.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/worksheets/sheet2.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/><Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
</Types>"#;
const APP_XML: &'static str = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><Template></Template><TotalTime>11</TotalTime><Application>spreadsheet-rs/0.0.1</Application></Properties>"#;
const CORE_XML: &'static str = r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dcterms:created xsi:type="dcterms:W3CDTF">XXXXXXXXXX</dcterms:created><dc:creator></dc:creator><dc:description></dc:description><dc:language>ja-JP</dc:language><cp:lastModifiedBy></cp:lastModifiedBy><dcterms:modified xsi:type="dcterms:W3CDTF">XXXXXXXXXX</dcterms:modified><cp:revision>6</cp:revision><dc:subject></dc:subject><dc:title></dc:title></cp:coreProperties>"#;
const RELS: &'static str = "_rels/.rels";
const RELS_CONTENT: &'static str = r#"<?xml version="1.0" encoding="UTF-8"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/><Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>
</Relationships>"#;

#[derive(Debug)]
pub enum XlsxError {
    Io(io::Error),
    Xml(quick_xml::errors::Error),
    Zip(zip::result::ZipError),
    Uft8(FromUtf8Error),
}

impl From<io::Error> for XlsxError {
    fn from(err: io::Error) -> XlsxError {
        XlsxError::Io(err)
    }
}

impl From<quick_xml::errors::Error> for XlsxError {
    fn from(err: quick_xml::errors::Error) -> XlsxError {
        XlsxError::Xml(err)
    }
}

impl From<zip::result::ZipError> for XlsxError {
    fn from(err: zip::result::ZipError) -> XlsxError {
        XlsxError::Zip(err)
    }
}

impl From<FromUtf8Error> for XlsxError {
    fn from(err: FromUtf8Error) -> XlsxError {
        XlsxError::Uft8(err)
    }
}

type Result<T> = result::Result<T, XlsxError>;

pub fn read(path: &Path) -> Result<Book> {
    let file = File::open(path)?;
    let dir = TempDir::new("shreadsheet")?;
    match unzip(&file, &dir) {
        Ok(_) => {},
        Err(err) => {
            dir.close()?;
            return Err(XlsxError::Zip(err));
        }
    }
    let mut book = Book::new();
    {
        let styles = read_styles::read(&dir)?;
        let rels = read_workbook_xml_rels::read(&dir)?;
        let mut rels_map = HashMap::new();
        for r in &rels {
            rels_map.insert(r.get("id").unwrap(), r.get("target").unwrap());
        }
        let sheets = read_workbook::read(&dir)?;
        let shared_strings = read_shared_strings::read(&dir)?;
        for s in &sheets {
            let sheet_target = rels_map.get(s.get("rid").unwrap()).unwrap();
            book.add_sheet(
                read_sheet::read(
                    &dir, s.get("name").unwrap(), 
                    sheet_target, 
                    &shared_strings, 
                    &styles)?);
        }
    }
    dir.close()?;
    Ok(book)
}

pub fn write(book: &Book, path: &Path) -> result::Result<(), XlsxError> {
    let dir = TempDir::new("shreadsheet")?;
    let now = Utc::now();
    let now_str = now.format("%Y-%m-%dT%H:%M:%SZ").to_string();
    let _ = make_static_file(
        &dir, RELS, 
        RELS_CONTENT, 
        Some("_rels"))?;
    let _ = make_static_file(
        &dir, "[Content_Types].xml", 
        CONTENT_TYPE_XML, 
        None)?;
    let _ = make_static_file(
        &dir, "docProps/app.xml", 
        APP_XML, 
        Some("docProps"))?;
    let _ = make_static_file(
        &dir, "docProps/core.xml", 
        CORE_XML.replace("XXXXXXXXXX", now_str.as_str()).as_str(), 
        Some("docProps"))?;
    let format_map = write_styles::write(book, &dir)?;
    let shared_strings = write_shared_strings::write(book, &dir)?;
    let _ = write_workbook_xml_rels::write(book, &dir)?;
    let _ = write_workbook::write(book, &dir)?;
    let mut index = 1;
    for sheet in book.get_sheet_vec() {
        let _ = write_sheet::write(sheet, &dir, &shared_strings, index, &format_map)?;
        index = index + 1;
    }
    write_to_file(path, &dir)?;
    dir.close()?;
    Ok(())
}