Parse IDML index topics in shared model

This commit is contained in:
Dylan M. Taylor committed 2026-11-13 09:32:56 -05:00
1 parent 7408ef8cc6
commit ff0cbc3a13
2 files changed
+58 -3

No files matched your search

+3 -2
View File
@@ -46,8 +46,9 @@ pub use spread::{
};
pub use story::{
Ace, AnchoredObjectSetting, AnchoredObjectValues, CONTAINERS, Cell, CellOptions, Container, ContainerKind, ContentPart,
IndexCrossReferenceValues, IndexValues, PageReference, Range, SavedCrossReference, SavedCrossReferencePart, Story, StoryAnchor, StoryPreference,
Table, TableChild, TableColumn, TableLayout, TableRow, TextNode, TrackedChangeKind, stories,
IndexCrossReferenceValues, IndexDocument, IndexReference, IndexTopicPath, IndexValues, PageReference, Range, SavedCrossReference,
SavedCrossReferencePart, Story, StoryAnchor, StoryPreference, Table, TableChild, TableColumn, TableLayout, TableRow, TextNode, TrackedChangeKind,
stories,
};
use crate::value::{matrix, nums};
+55 -1
View File
@@ -2,7 +2,7 @@
//! anchored page items, hyperlink and change containers).
use craft_xml::{El, Local, Node};
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashMap};
use super::{PageItem, Values, tidy};
@@ -206,6 +206,60 @@ pub struct IndexCrossReferenceValues {
pub target: String,
}
/// A topic path and its sort keys, as they are saved on nested IDML `Topic` elements.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct IndexTopicPath {
pub path: Vec<String>,
pub sort: Vec<String>,
}
/// An IDML index cross-reference as stored under an index topic.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct IndexReference {
pub from: IndexTopicPath,
pub referenced_topic: Option<String>,
pub reference_type: Option<String>,
}
/// Parsed IDML index topics and cross-references.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct IndexDocument {
pub topics: HashMap<String, IndexTopicPath>,
pub cross_references: Vec<IndexReference>,
}
impl IndexDocument {
pub fn from_el(element: &El) -> Self {
let mut result = Self::default();
let mut stack: Vec<(&El, IndexTopicPath)> =
element.elements().filter(|child| child.local() == "Topic").map(|topic| (topic, IndexTopicPath::default())).collect();
while let Some((topic, prefix)) = stack.pop() {
let name = topic.attr("Name").unwrap_or_default().to_string();
let mut current = prefix.clone();
current.path.push(name);
if let Some(key) = topic.attr("SortOrder").filter(|key| !key.is_empty()) {
current.sort.resize(prefix.path.len(), String::new());
current.sort.push(key.to_string());
}
if let Some(self_id) = topic.attr("Self") {
result.topics.insert(self_id.to_string(), current.clone());
}
for child in topic.elements() {
if child.local() == "CrossReference" {
result.cross_references.push(IndexReference {
from: current.clone(),
referenced_topic: child.attr("ReferencedTopic").map(str::to_string),
reference_type: child.attr("CrossReferenceType").map(str::to_string),
});
} else if child.local() == "Topic" {
stack.push((child, current.clone()));
}
}
}
result
}
}
impl IndexValues {
/// Builds the IDML `Self` value for a topic path.
pub fn topic_self(path: &[String]) -> String {