spv::{
SpvArchive,
legacy_bin::LegacyBin,
- read::{ReadSeek, structure::OutlineItem},
+ read::{ReadSeek, legacy_xml::Visualization, structure::OutlineItem},
},
};
use std::{
collections::HashMap,
fmt::Display,
- io::{Cursor, Read},
+ io::{BufReader, Cursor, Read},
path::PathBuf,
sync::Arc,
};
ConvertTableLook,
/// Print data values in legacy tables.
+ ///
+ /// Data values come from `_tableData.bin` members inside the SPV files.
+ /// They do not require reading the corresponding `_table.xml` files.
LegacyData,
+ /// Print data series in legacy tables.
+ ///
+ /// The series come from `_tableData.bin` members inside the SPV files, as
+ /// transformed by instructions in their paired `_table.xml` files.
+ LegacySeries,
+
/// Prints contents.
View,
}
Mode::GetTableLook => "get-table-look",
Mode::ConvertTableLook => "convert-table-look",
Mode::LegacyData => "legacy-data",
+ Mode::LegacySeries => "legacy-series",
Mode::View => "view",
}
}
Mode::Directory => self.directory(),
Mode::View => self.view(),
Mode::LegacyData => self.legacy_data(),
+ Mode::LegacySeries => self.legacy_series(),
Mode::GetTableLook => todo!(),
Mode::ConvertTableLook => todo!(),
}
}
Ok(())
}
+
+ fn legacy_series(self) -> Result<()> {
+ let (mut archive, items) = self.read_outline()?;
+ for item in items {
+ for item in item.iter_in_order() {
+ if let Some(spv_info) = item.spv_info()
+ && let Some(members) = &spv_info.members
+ && let SpvMembers::LegacyTable { xml, binary } = &members
+ {
+ /// Read and decode binary file.
+ let mut bin_member = archive.0.by_name(&binary)?;
+ let mut bin_data = Vec::with_capacity(bin_member.size() as usize);
+ bin_member.read_to_end(&mut bin_data)?;
+ let mut cursor = Cursor::new(bin_data);
+ let legacy_bin = LegacyBin::read(&mut cursor).map_err(|e| {
+ e.with_message(format!(
+ "While parsing {binary:?} as legacy binary SPV member"
+ ))
+ })?;
+ let data = legacy_bin.decode(&mut |w| eprintln!("{w}"));
+ drop(bin_member);
+
+ /// Read decode series in XML file.
+ let member = BufReader::new(archive.0.by_name(&xml)?);
+ let visualization: Visualization = match serde_path_to_error::deserialize(
+ &mut quick_xml::de::Deserializer::from_reader(member),
+ ) {
+ Ok(result) => result,
+ Err(error) => panic!("{error:?}"),
+ };
+ let series = visualization.decode_series(data, &mut |w| {
+ eprintln!("{w}");
+ });
+
+ let n_values = series
+ .values()
+ .map(|map| map.values.len())
+ .max()
+ .unwrap_or(0);
+ let index = Dimension::new(
+ Group::new("Index")
+ .with_multiple(Leaf::numbers(0..n_values))
+ .with_label_shown(),
+ );
+ let variables = Dimension::new(Group::new("Series").with_multiple(
+ series.values().map(|series| {
+ series
+ .name
+ .replace("categories", "\ncategories")
+ .replace("labels", "\nlabels")
+ .replace("group", "\ngroup")
+ .replace("Label", "\nLabel")
+ }),
+ ));
+ let mut pivot_table =
+ PivotTable::new([(Axis3::Y, index), (Axis3::X, variables)]);
+ for (series_index, series) in series.values().enumerate() {
+ for (value_index, data_value) in series.values.iter().enumerate() {
+ pivot_table.insert(
+ [value_index, series_index],
+ Value::new_datum(&data_value.value),
+ );
+ }
+ }
+ println!("{pivot_table}");
+ }
+ }
+ }
+ Ok(())
+ }
}
fn print_item_directory<T>(item: &T, level: usize, show_member_names: bool)
pub fn decode(
&self,
- data: IndexMap<String, IndexMap<String, Vec<DataValue>>>,
+ binary_data: IndexMap<String, IndexMap<String, Vec<DataValue>>>,
look: Look,
warn: &mut dyn FnMut(LegacyXmlWarning),
) -> Result<PivotTable, super::Error> {
};
let caption = LabelFrame::decode_label(caption_labels, &footnotes);
- let series = self.decode_series(data, warn);
+ let series = self.decode_series(binary_data, warn);
let (mut dims, current_layer) = self.decode_dimensions(graph, &series, &footnotes);
let cell_footnotes = graph
}
pub struct Series {
- name: String,
+ pub name: String,
label: Option<String>,
- values: Vec<DataValue>,
+ pub values: Vec<DataValue>,
map: Map,
affixes: Vec<Affix>,
coordinate_to_index: RefCell<BTreeMap<usize, CategoryLocator>>,