Skip to content

Commit

Permalink
feat(sheet): support inline str in sheet data
Browse files Browse the repository at this point in the history
  • Loading branch information
zitsen committed Jan 17, 2021
1 parent 9428144 commit 2084001
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 39 deletions.
16 changes: 8 additions & 8 deletions src/document/spreadsheet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,17 @@ impl SpreadsheetParts {
let workbook = {
let package = package.borrow();
let part = package.get_part("xl/workbook.xml").unwrap();
WorkbookPart::from_xml_reader(part.as_part_bytes()).expect("workbook part error")
WorkbookPart::from_xml_reader(part.as_part_bytes()).expect("workbook main part error")
};
let shared_strings = {
let package = package.borrow();
let part = package.get_part("xl/sharedStrings.xml").unwrap();
SharedStringsPart::from_xml_reader(part.as_part_bytes()).expect("workbook part error")
SharedStringsPart::from_xml_reader(part.as_part_bytes()).expect("workbook shared strings error")
};
let styles = {
let package = package.borrow();
let part = package.get_part("xl/styles.xml").unwrap();
StylesPart::from_xml_reader(part.as_part_bytes()).expect("workbook part error")
StylesPart::from_xml_reader(part.as_part_bytes()).expect("workbook styles error")
};
let mut this = Self {
package: package,
Expand Down Expand Up @@ -120,7 +120,7 @@ impl SpreadsheetParts {
.get_part(&format!("xl/{}", worksheet_uri))
.expect("get worksheet part by uri");
let sheet =
WorksheetPart::from_xml_reader(part.as_part_bytes()).expect("parse worksheet");
WorksheetPart::from_xml_reader(part.as_part_bytes()).expect("parse worksheet error");

self.worksheets.insert(worksheet_uri.into(), sheet);
}
Expand Down Expand Up @@ -421,11 +421,11 @@ impl<'a> Cell<'a> {
),
cell::CellType::Styled(style_id) => self
.sheet
.to_cell_value(&inner.v, style_id)
.to_cell_value(&inner.as_raw_str(), style_id)
.expect("format with cell style"),
cell::CellType::StyledNumber(style_id) => self
.sheet
.to_cell_value(&inner.v, style_id)
.to_cell_value(&inner.as_raw_str(), style_id)
.expect("format with cell style"),
};
Some(value)
Expand All @@ -448,11 +448,11 @@ impl<'a> Cell<'a> {
.expect(&format!("shared string not found {}", shared_string_id)),
cell::CellType::Styled(style_id) => self
.sheet
.format_cell_with(&inner.v, style_id)
.format_cell_with(&inner.as_raw_str(), style_id)
.expect("format with cell style"),
cell::CellType::StyledNumber(style_id) => self
.sheet
.format_cell_with(&inner.v, style_id)
.format_cell_with(&inner.as_raw_str(), style_id)
.expect("format with cell style"),
};
Some(value)
Expand Down
9 changes: 3 additions & 6 deletions src/document/spreadsheet/shared_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,12 @@ pub struct SharedStringsPart {
#[serde(flatten)]
namespaces: Namespaces,
#[serde(rename = "si")]
strings: Vec<SharedString>,
strings: Option<Vec<SharedString>>,
}

impl SharedStringsPart {
pub fn get_shared_string(&self, idx: usize) -> Option<&str> {
match self.strings.get(idx) {
None => None,
Some(ss) => Some(ss.as_str()),
}
self.strings.as_ref().and_then(|ss| ss.get(idx)).map(|ss| ss.as_str())
}
}

Expand Down Expand Up @@ -142,7 +139,7 @@ impl SharedStringsPart {
},
]);
xml.write_event(Event::Start(elem))?;
for si in &self.strings {
for si in self.strings.as_ref().unwrap_or(&vec![]) {
let elem = BytesStart::borrowed_name(SHARED_STRING_TAG.as_bytes());
xml.write_event(Event::Start(elem))?;
quick_xml::se::to_writer(xml.inner(), &si.t)?;
Expand Down
7 changes: 4 additions & 3 deletions src/document/spreadsheet/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ impl OpenXmlDeserializeDefault for NumberFormat {}
#[serde(rename = "numFmts")]
pub struct NumberFormats {
#[serde(rename = "numFmt")]
num_fmt: Vec<NumberFormat>,
num_fmt: Option<Vec<NumberFormat>>,
}
impl OpenXmlDeserializeDefault for NumberFormats {}

Expand All @@ -35,7 +35,7 @@ pub(crate) mod font {
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename = "sz")]
pub struct FontSize {
val: usize,
val: f64,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename = "name")]
Expand Down Expand Up @@ -354,7 +354,8 @@ impl StylesPart {
self.num_fmts
.as_ref()
//.and_then(|inner| inner.num_fmt.get(id))
.and_then(|inner| inner.num_fmt.iter().find(|nf| nf.id == id))
.and_then(|inner| inner.num_fmt.as_ref())
.and_then(|inner| inner.iter().find(|nf| nf.id == id))
}
pub fn get_font(&self, id: usize) -> Option<&Font> {
self.fonts.as_ref().and_then(|fonts| fonts.fonts.get(id))
Expand Down
8 changes: 5 additions & 3 deletions src/document/spreadsheet/workbook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ pub struct FileVersion {

#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", rename = "workbookPr")]
pub struct WorkbookPr {}
pub struct WorkbookPr {
date1904: Option<bool>,
}

#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", rename = "workbookView")]
Expand Down Expand Up @@ -57,11 +59,11 @@ pub struct CalcPr {
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WorkbookPart {
pub file_version: FileVersion,
pub file_version: Option<FileVersion>,
pub book_views: BookViews,
pub workbook_pr: WorkbookPr,
pub sheets: Sheets,
pub calc_pr: CalcPr,
pub calc_pr: Option<CalcPr>,
#[serde(flatten)]
namespaces: Namespaces,
}
Expand Down
80 changes: 61 additions & 19 deletions src/document/spreadsheet/worksheet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,12 @@ impl Dimension {
let re: regex::Regex = regex::Regex::new(r"(?P<col>[A-Z]+)(?P<row>\d+)").unwrap();
let cap = re.captures(range).unwrap();
let col = cap.name("col").unwrap().as_str();
let row = cap.name("row").unwrap().as_str().parse().unwrap_or_default();
let row = cap
.name("row")
.unwrap()
.as_str()
.parse()
.unwrap_or_default();
fn col_to_idx(col: &str) -> usize {
if col.is_empty() {
return 0;
Expand All @@ -73,7 +78,6 @@ impl Dimension {
for (i, c) in col.chars().rev().enumerate() {
let c = c.to_digit(36).unwrap();
idx += c * 26u32.pow(i as _);

}
return idx as usize;
}
Expand All @@ -99,43 +103,65 @@ pub struct SheetFormatPr {
outline_level_row: Option<f32>,
outline_level_col: Option<f32>,
}

#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", rename = "v")]
pub struct SheetValue {
v: CellValue,
#[serde(rename_all = "camelCase", rename = "is")]
pub struct SheetCellIs {
t: Option<String>,
}

// #[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
// #[serde(rename_all = "camelCase", rename = "v")]
// pub struct SheetValue {
// v: Option<CellValue>,
// }

#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", rename = "c")]
pub struct SheetCol {
pub r: String,
pub t: Option<String>,
pub s: Option<usize>,
#[serde(rename = "$value")]
pub v: String,
pub is: Option<SheetCellIs>,
//#[serde(rename = "$value")]
// pub v: String,
pub v: Option<String>,
}

impl SheetCol {
pub fn as_raw_str(&self) -> &str {
self.v.as_str()
if let Some(is) = self.is.as_ref() {
return is.t.as_ref().expect("inline str error")
} else if let Some(v) = self.v.as_ref() {
return v.as_str();
} else {
unreachable!()
}
// self.v.as_str()
}
pub fn raw_value(&self) -> CellValue {
CellValue::String(self.v.to_string())

CellValue::String(self.as_raw_str().to_string())
}
pub fn cell_type(&self) -> CellType {
match (self.t.as_ref(), self.s.as_ref()) {
(None, None) => CellType::Raw,
(Some(t), None) => match t {
s if s == "s" => CellType::Shared(self.v.parse().expect("sharedString id not valid")),
s if s == "s" => {
CellType::Shared(self.v.as_ref().expect("shared string has no id").parse().expect("sharedString id not valid"))
}
n if n == "n" => CellType::Number,
t => unimplemented!("cell type not supported: {}" , t),
}
t if t == "inlineStr" => CellType::Raw,
t => unimplemented!("cell type not supported: {}", t),
},
(None, Some(s)) => CellType::Styled(*s),
(Some(t), Some(s)) => match t {
t if t == "s" => CellType::Shared(self.v.parse().expect("sharedString id not valid")),
t if t == "s" => {
CellType::Shared(self.v.as_ref().expect("shared string has no id").parse().expect("sharedString id not valid"))
}
t if t == "n" => CellType::StyledNumber(*s),
t => unimplemented!("cell type not supported: {}" , t),
}
t if t == "inlineStr" => CellType::Raw,
t => unimplemented!("cell type not supported: {}", t),
},
}
// if let Some(t) = self.t.as_ref() {
// match t {
Expand All @@ -154,6 +180,9 @@ impl SheetCol {
#[serde(rename = "row")]
pub struct SheetRow {
pub r: usize,
#[serde(rename = "customHeight")]
pub custom_height: Option<bool>,
pub ht: Option<f64>,
pub spans: Option<String>,
#[serde(rename = "c")]
pub cols: Vec<SheetCol>,
Expand Down Expand Up @@ -183,13 +212,13 @@ pub struct HeaderFooter {}
pub struct WorksheetPart {
#[serde(flatten)]
namespaces: Namespaces,
pub sheet_pr: SheetPr,
pub sheet_pr: Option<SheetPr>,
pub dimension: Option<Dimension>,
pub sheet_views: Option<SheetViews>,
pub sheet_format_pr: Option<SheetFormatPr>,
pub sheet_data: Option<SheetData>,
pub page_margins: PageMargins,
pub header_footer: HeaderFooter,
pub page_margins: Option<PageMargins>,
pub header_footer: Option<HeaderFooter>,
}

impl WorksheetPart {
Expand Down Expand Up @@ -231,6 +260,7 @@ impl OpenXmlSerialize for WorksheetPart {

#[test]
fn serde() {
// let xml = include_str!("../../../tests/inline-str/xl/worksheets/sheet1.xml");
let xml = include_str!("../../../examples/simple-spreadsheet/xl/worksheets/sheet1.xml");
println!("{}", xml);
let worksheet = WorksheetPart::from_xml_str(xml).unwrap();
Expand All @@ -248,3 +278,15 @@ fn serde() {
println!("{:?}", worksheet2);
assert_eq!(worksheet, worksheet2);
}

#[test]
fn cell() {
let xml = r#"
<c r="B2" s="1" t="inlineStr">
<is>
<t>&#21776;&#33564;</t>
</is>
</c>"#;
let c: SheetCol = quick_xml::de::from_str(xml).unwrap();
println!("{:?}", c);
}

0 comments on commit 2084001

Please sign in to comment.