cleanup
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 2 Jan 2026 04:18:52 +0000 (20:18 -0800)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 2 Jan 2026 04:18:52 +0000 (20:18 -0800)
rust/pspp/src/spv/read/legacy_xml.rs

index aabd804a7fad5b739458896ac12e3f0732d430f0..751c606ac37c2721c70f38d2754f278140cf634f 100644 (file)
@@ -264,6 +264,53 @@ impl Visualization {
         series
     }
 
+    /// Decodes the table of footnotes from the `graph` and the collection of
+    /// all the footnote labels.  Any [Value] might refer to footnotes, so it's
+    /// important to process the footnotes early to ensure that those references
+    /// can be resolved.
+    fn decode_footnotes(&self, graph: &Graph, footnote_labels: &[&Label]) -> pivot::Footnotes {
+        let mut footnote_builder = BTreeMap::<usize, Footnote>::new();
+        if let Some(f) = &graph.interval.footnotes {
+            f.decode(&mut footnote_builder);
+        }
+        for child in &graph.interval.labeling.children {
+            if let LabelingChild::Footnotes(f) = child {
+                f.decode(&mut footnote_builder);
+            }
+        }
+        for label in footnote_labels {
+            for (index, text) in label.text().iter().enumerate() {
+                if let Some(uses_reference) = text.uses_reference {
+                    let entry = footnote_builder
+                        .entry(uses_reference.get() - 1)
+                        .or_default();
+                    if index % 2 == 1 {
+                        entry.content = text.text.strip_suffix('\n').unwrap_or(&text.text).into();
+                    } else {
+                        entry.marker = Some(
+                            text.text
+                                .trim_end()
+                                .strip_suffix('.')
+                                .unwrap_or(&text.text)
+                                .into(),
+                        );
+                    }
+                }
+            }
+        }
+        let mut footnotes = Vec::new();
+        for (index, footnote) in footnote_builder {
+            while footnotes.len() < index {
+                footnotes.push(pivot::Footnote::default());
+            }
+            footnotes.push(
+                pivot::Footnote::new(footnote.content)
+                    .with_marker(footnote.marker.map(|s| Value::new_user_text(s))),
+            );
+        }
+        pivot::Footnotes::from_iter(footnotes)
+    }
+
     pub fn decode(
         &self,
         data: IndexMap<String, IndexMap<String, Vec<DataValue>>>,
@@ -314,58 +361,7 @@ impl Visualization {
             }
         }
 
-        // Footnotes.
-        //
-        // Any [Value] might refer to footnotes, so it's important to process
-        // the footnotes early to ensure that those references can be resolved.
-        // There is a possible problem that a footnote might itself reference an
-        // as-yet-unprocessed footnote, but that's OK because footnote
-        // references don't actually look at the footnote contents but only
-        // resolve a pointer to where the footnote will go later.
-        //
-        // Before we really start, create all the footnotes we'll fill in.  This
-        // is because sometimes footnotes refer to themselves or to each other
-        // and we don't want to reject those references.
-        let mut footnote_builder = BTreeMap::<usize, Footnote>::new();
-        if let Some(f) = &graph.interval.footnotes {
-            f.decode(&mut footnote_builder);
-        }
-        for child in &graph.interval.labeling.children {
-            if let LabelingChild::Footnotes(f) = child {
-                f.decode(&mut footnote_builder);
-            }
-        }
-        for label in &labels[Purpose::Footnote] {
-            for (index, text) in label.text().iter().enumerate() {
-                if let Some(uses_reference) = text.uses_reference {
-                    let entry = footnote_builder
-                        .entry(uses_reference.get() - 1)
-                        .or_default();
-                    if index % 2 == 1 {
-                        entry.content = text.text.strip_suffix('\n').unwrap_or(&text.text).into();
-                    } else {
-                        entry.marker = Some(
-                            text.text
-                                .trim_end()
-                                .strip_suffix('.')
-                                .unwrap_or(&text.text)
-                                .into(),
-                        );
-                    }
-                }
-            }
-        }
-        let mut footnotes = Vec::new();
-        for (index, footnote) in footnote_builder {
-            while footnotes.len() < index {
-                footnotes.push(pivot::Footnote::default());
-            }
-            footnotes.push(
-                pivot::Footnote::new(footnote.content)
-                    .with_marker(footnote.marker.map(|s| Value::new_user_text(s))),
-            );
-        }
-        let footnotes = pivot::Footnotes::from_iter(footnotes);
+        let footnotes = self.decode_footnotes(graph, &labels[Purpose::Footnote]);
 
         let title = LabelFrame::decode_label(&labels[Purpose::Title], &footnotes);
         let mut caption_labels = &labels[Purpose::SubTitle];