From: Ben Pfaff Date: Wed, 5 Nov 2025 15:50:43 +0000 (-0800) Subject: legacy xml starts to work X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=543d61858640b0bdf8f0fe8b4d25da46a2b21bc9;p=pspp legacy xml starts to work --- diff --git a/rust/doc/src/invoking/pspp-show-spv.md b/rust/doc/src/invoking/pspp-show-spv.md index a31ff548c3..fafbbfa24d 100644 --- a/rust/doc/src/invoking/pspp-show-spv.md +++ b/rust/doc/src/invoking/pspp-show-spv.md @@ -1,7 +1,7 @@ # Inspecting SPSS Viewer Files -The `pspp show-spv` command reads SPSS Viewer (SPV) files, which -usually have `.sav` extension, and produces a report. The basic +The `pspp show-spv` command reads SPSS Viewer (SPV) files, whose names +usually have an `.spv` extension, and produces a report. The basic syntax is: ``` diff --git a/rust/pspp/src/output/spv.rs b/rust/pspp/src/output/spv.rs index b47911c6d2..f42c478dac 100644 --- a/rust/pspp/src/output/spv.rs +++ b/rust/pspp/src/output/spv.rs @@ -443,16 +443,19 @@ impl Table { Ok(result) => result, Err(error) => panic!("{error:?}"), }; - visualization - .decode( - data, - self.properties - .as_ref() - .map_or_else(Look::default, |properties| properties.clone().into()), - ) - .unwrap()/*XXX*/; - - Ok(PivotTable::new([]).into_item()) + let pivot_table = visualization.decode( + data, + self.properties + .as_ref() + .map_or_else(Look::default, |properties| properties.clone().into()), + )?; + + Ok(pivot_table.into_item().with_spv_info( + SpvInfo::new(structure_member).with_members(SpvMembers::Legacy { + xml: xml_member_name.clone(), + binary: bin_member_name.clone(), + }), + )) } } } diff --git a/rust/pspp/src/output/spv/legacy_bin.rs b/rust/pspp/src/output/spv/legacy_bin.rs index f1e0e46342..dd9a2ccb26 100644 --- a/rust/pspp/src/output/spv/legacy_bin.rs +++ b/rust/pspp/src/output/spv/legacy_bin.rs @@ -105,6 +105,7 @@ impl DataValue { } pub fn as_pivot_value(&self, format: Format) -> Value { + dbg!(format.type_()); if format.type_().category() == Category::Date && let Some(s) = self.value.as_string() && let Ok(date_time) = diff --git a/rust/pspp/src/output/spv/legacy_xml.rs b/rust/pspp/src/output/spv/legacy_xml.rs index fd91c341e4..2bfec0fbc3 100644 --- a/rust/pspp/src/output/spv/legacy_xml.rs +++ b/rust/pspp/src/output/spv/legacy_xml.rs @@ -367,8 +367,8 @@ impl Visualization { } } - fn decode_dimension( - variables: &[(&Series, usize)], + fn decode_dimension<'a>( + variables: &[(&'a Series, usize)], axes: &HashMap, styles: &HashMap<&str, &Style>, a: Axis3, @@ -376,7 +376,8 @@ impl Visualization { rotate_inner_column_labels: &mut bool, rotate_outer_row_labels: &mut bool, footnotes: &pivot::Footnotes, - ) -> Dimension { + dims: &mut Vec>, + ) { let base_level = variables[0].1; let show_label = if let Ok(a) = Axis2::try_from(a) && let Some(axis) = axes.get(&(base_level + variables.len())) @@ -419,26 +420,16 @@ impl Visualization { .map(|(series, _level)| *series) .collect::>(); - // Find the first row for each category, then drop missing - // categories and count what's left. - let max_cat = variables[0].max_category().unwrap()/*XXX*/; - let mut cat_rows = vec![None; max_cat + 1]; - for (index, value) in variables[0].values.iter().enumerate() { - if let Some(row) = value.category() { - cat_rows[row].get_or_insert(index); - } - } - let cat_rows = cat_rows.into_iter().flatten().collect::>(); - // Make leaf categories. - let mut cats = Vec::with_capacity(cat_rows.len()); - for (index, cat_row) in cat_rows.into_iter().enumerate() { - let dv = &variables[0].values[cat_row]; - let name = variables[0].new_name(dv, footnotes); - cats.push((Category::from(Leaf::new(name)), index..index + 1)); - } - if cats.is_empty() { - todo!() + let mut coordinate_to_index = HashMap::new(); + let mut cats = Vec::new(); + for (index, value) in variables[0].values.iter().enumerate() { + let Some(row) = value.category() else { + continue; + }; + coordinate_to_index.insert(row, index); + let name = variables[0].new_name(value, footnotes); + cats.push((Category::from(Leaf::new(name)), cats.len()..cats.len() + 1)); } // Now group them, in one pass per grouping variable, innermost first. @@ -473,7 +464,7 @@ impl Visualization { cats = next_cats; } - Dimension::new( + let dimension = Dimension::new( Group::new( variables[0] .label @@ -482,7 +473,13 @@ impl Visualization { ) .with_multiple(cats.into_iter().map(|(category, _range)| category)) .with_show_label(show_label), - ) + ); + dims.push(Dim { + axis: a, + dimension: Some(dimension), + coordinate: variables[0], + coordinate_to_index, + }); } fn decode_dimensions<'a, 'b>( @@ -496,8 +493,7 @@ impl Visualization { rotate_outer_row_labels: &mut bool, footnotes: &pivot::Footnotes, level_ofs: usize, - dimensions: &mut Vec<(Axis3, pivot::Dimension)>, - coordinates: &mut Vec<&'b Series>, + dims: &mut Vec>, ) { let variables = variables .into_iter() @@ -514,27 +510,6 @@ impl Visualization { if let Some((var, level)) = var { dim_vars.push((var, level)); } else if !dim_vars.is_empty() { - coordinates.push(dim_vars[0].0); - dimensions.push(( - a, - decode_dimension( - &dim_vars, - axes, - styles, - a, - look, - rotate_inner_column_labels, - rotate_outer_row_labels, - footnotes, - ), - )); - dim_vars.clear(); - } - } - if !dim_vars.is_empty() { - coordinates.push(dim_vars[0].0); - dimensions.push(( - a, decode_dimension( &dim_vars, axes, @@ -544,9 +519,31 @@ impl Visualization { rotate_inner_column_labels, rotate_outer_row_labels, footnotes, - ), - )); + dims, + ); + dim_vars.clear(); + } } + if !dim_vars.is_empty() { + decode_dimension( + &dim_vars, + axes, + styles, + a, + look, + rotate_inner_column_labels, + rotate_outer_row_labels, + footnotes, + dims, + ); + } + } + + struct Dim<'a> { + axis: Axis3, + dimension: Option, + coordinate: &'a Series, + coordinate_to_index: HashMap, } let mut rotate_inner_column_labels = false; @@ -556,8 +553,7 @@ impl Visualization { .first() .map(|child| child.variables()) .unwrap_or_default(); - let mut dimensions = Vec::new(); - let mut coordinates = Vec::new(); + let mut dims = Vec::new(); decode_dimensions( columns.into_iter().map(|vr| vr.reference.as_str()), &series, @@ -569,8 +565,7 @@ impl Visualization { &mut rotate_outer_row_labels, &footnotes, 1, - &mut dimensions, - &mut coordinates, + &mut dims, ); let rows = cross .get(1) @@ -587,8 +582,7 @@ impl Visualization { &mut rotate_outer_row_labels, &footnotes, 1 + columns.len(), - &mut dimensions, - &mut coordinates, + &mut dims, ); let mut level_ofs = columns.len() + rows.len() + 1; @@ -604,16 +598,20 @@ impl Visualization { &mut rotate_outer_row_labels, &footnotes, level_ofs, - &mut dimensions, - &mut coordinates, + &mut dims, ); level_ofs += layers.len(); } + let dimensions = dims + .iter_mut() + .map(|dim| (dim.axis, dim.dimension.take().unwrap())) + .collect::>(); + let mut pivot_table = PivotTable::new(dimensions); let cell = series.get("cell").unwrap()/*XXX*/; - let mut coords = Vec::with_capacity(coordinates.len()); + let mut coords = Vec::with_capacity(dims.len()); let (cell_formats, format_map) = graph.interval.labeling.decode_format_map(&series); let cell_footnotes = graph @@ -627,9 +625,14 @@ impl Visualization { }); for (i, cell) in cell.values.iter().enumerate() { coords.clear(); - for series in &coordinates { + for dim in &dims { // XXX indexing of values, and unwrap - coords.push(series.values[i].category().unwrap()); + let coordinate = dim.coordinate.values[i].category().unwrap(); + let index = match dim.coordinate_to_index.get(&coordinate) { + Some(index) => *index, + None => panic!("can't find {coordinate}"), + }; + coords.push(index); } let format = if let Some(cell_formats) = &cell_formats { diff --git a/rust/pspp/src/show_spv.rs b/rust/pspp/src/show_spv.rs index c2a0fd94b6..fa399f9067 100644 --- a/rust/pspp/src/show_spv.rs +++ b/rust/pspp/src/show_spv.rs @@ -42,7 +42,7 @@ pub struct ShowSpv { show_member_names: bool, } -/// What to show in a system file. +/// What to show in a viewer file. #[derive(Clone, Copy, Debug, PartialEq, ValueEnum)] enum Mode { /// List tables and other items. @@ -54,6 +54,9 @@ enum Mode { /// Reads `.tlo` or `.stt` TableLook and outputs as `.stt` format. ConvertTableLook, + + /// Prints contents. + View, } impl Mode { @@ -62,6 +65,7 @@ impl Mode { Mode::Directory => "directory", Mode::GetTableLook => "get-table-look", Mode::ConvertTableLook => "convert-table-look", + Mode::View => "view", } } } @@ -83,6 +87,14 @@ impl ShowSpv { } Ok(()) } + Mode::View => { + let item = Item::from_spv_file(&self.input)?.0; + let item = self.criteria.apply(item); + for child in item.details.children() { + println!("{child}"); + } + Ok(()) + } Mode::GetTableLook => todo!(), Mode::ConvertTableLook => todo!(), }