pub struct TreeDiff {
pub root_path: String,
pub changes: Vec<FieldChangeEvent>,
pub from_element: ElementData,
pub to_element: ElementData,
pub added: Vec<ElementData>,
pub removed: Vec<ElementData>,
pub child_diffs: Vec<TreeDiff>,
}Expand description
A hierarchical diff between two versions of a USLM document tree
This struct captures all changes between two versions of the same legislative
element and its children. It mirrors the tree structure of USLMElement,
with diffs computed recursively for all matching children.
§Structure
The diff includes:
- Field changes: Text modifications to the element’s own content fields
- Added elements: New child elements in the new version
- Removed elements: Child elements that existed in the old version but not the new
- Child diffs: Recursive diffs for child elements that exist in both versions
§Examples
use words_to_data::{diff::TreeDiff, uslm::parser::parse};
// Parse two versions of a document
let old_doc = parse("tests/test_data/usc/2025-07-18/usc07.xml", "2025-07-18").unwrap();
let new_doc = parse("tests/test_data/usc/2025-07-30/usc07.xml", "2025-07-30").unwrap();
// Compute the diff
let diff = TreeDiff::from_elements(&old_doc, &new_doc);
// Examine changes
println!("Field changes: {}", diff.changes.len());
println!("Elements added: {}", diff.added.len());
println!("Elements removed: {}", diff.removed.len());Fields§
§root_path: StringThe structural path of the element being compared
changes: Vec<FieldChangeEvent>Text content field changes for this element
from_element: ElementDataMetadata from the original version of this element
to_element: ElementDataMetadata from the new version of this element
added: Vec<ElementData>Child elements that were added in the new version
removed: Vec<ElementData>Child elements that were removed from the old version
child_diffs: Vec<TreeDiff>Recursive diffs for child elements present in both versions
Implementations§
Source§impl TreeDiff
impl TreeDiff
Sourcepub fn mention_regex(&self) -> Option<Regex>
pub fn mention_regex(&self) -> Option<Regex>
Generate a regex for searching for mentions of an element
Amendments and other legal texts tend to exclude chapters and titles when discussing legal references instead, they have a tendency to directly state references, and pieces of them. e.g.
“According to Section 174 (a)(2)(A)”
This function will generate compatible regexes for relevant strucutural elements to match those.
pub fn section_regex(&self) -> Option<Regex>
Sourcepub fn all_regexes(&self) -> Vec<Regex>
pub fn all_regexes(&self) -> Vec<Regex>
Generates a list of all candidate regexes for a TreeDiff
Sourcepub fn from_elements(
from_element: &USLMElement,
to_element: &USLMElement,
) -> TreeDiff
pub fn from_elements( from_element: &USLMElement, to_element: &USLMElement, ) -> TreeDiff
Compute the diff between two USLM element trees
Compares two versions of the same legislative element and computes all changes at both the current level and recursively through all children.
§Arguments
from_element- The original (older) version of the elementto_element- The new (newer) version of the element
§Panics
Panics if the two elements don’t have the same structural path, as they must represent the same logical element in different versions.
§Returns
A TreeDiff containing all detected changes between the two versions.
§Examples
let old = parse("tests/test_data/usc/2025-07-18/usc07.xml", "2025-07-18").unwrap();
let new = parse("tests/test_data/usc/2025-07-30/usc07.xml", "2025-07-30").unwrap();
let diff = TreeDiff::from_elements(&old, &new);
assert_eq!(diff.root_path, old.data.path);Sourcepub fn find(&self, path: &str) -> Option<&TreeDiff>
pub fn find(&self, path: &str) -> Option<&TreeDiff>
Search for a diff by its structural path
Recursively searches this element and all descendants for an element with the specified path. The path must be a fully qualified structural path (e.g., “uscode/title_7/chapter_1/section_1”).
§Arguments
path- The full structural path of the element to find
§Returns
Returns Some(&TreeDiff) if an element with the matching path is found,
or None if no such element exists in this tree.
Sourcepub fn calculate_amendment_similarities(
&self,
data: &Bill,
) -> HashMap<String, AmendmentSimilarity>
pub fn calculate_amendment_similarities( &self, data: &Bill, ) -> HashMap<String, AmendmentSimilarity>
Calculate the similarity of diffs in the TreeDiff with the amendment data from a bill
Returns a hashmap with the key being the root_path in the tree diff and the value being the similarity data
Sourcepub fn scan_for_mentions(
&self,
data: &Bill,
) -> HashMap<String, Vec<MentionMatch>>
pub fn scan_for_mentions( &self, data: &Bill, ) -> HashMap<String, Vec<MentionMatch>>
Scan all amendment texts for mentions of changed sections.
Uses the regexes from all_regexes() to find section mentions in each
amendment’s amending_text. This helps identify which amendments might
be responsible for changes at specific structural paths.
§Arguments
data- Bill data from a parsed bill
§Returns
A map from amendment_id to list of matches found in that amendment’s text. For each tree_diff_path, only the most specific (longest) match is kept.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for TreeDiff
impl<'de> Deserialize<'de> for TreeDiff
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for TreeDiff
impl StructuralPartialEq for TreeDiff
Auto Trait Implementations§
impl Freeze for TreeDiff
impl RefUnwindSafe for TreeDiff
impl Send for TreeDiff
impl Sync for TreeDiff
impl Unpin for TreeDiff
impl UnsafeUnpin for TreeDiff
impl UnwindSafe for TreeDiff
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more