1. General
The show_diffs parameter controls which differences appear in diff output
while maintaining correct equivalence determination.
This feature allows you to filter diff display based on whether differences are normative (affect equivalence) or informative (don’t affect equivalence).
2. Purpose
When comparing documents with both normative and informative differences, you may want to:
-
Show only normative differences: Focus on changes that make documents non-equivalent
-
Show only informative differences: View differences that don’t affect equivalence (e.g., comments when set to
:ignore) -
Show all differences: See both types (default behavior)
2.1. Common use case: XML comments
When comparing XML with comments: :ignore, comment differences are classified
as informative (they don’t affect equivalence). Using show_diffs: :normative
hides these comment diffs while showing only structural/content differences.
xml1 = <<~XML
<root>
<!-- Old comment -->
<element>value1</element>
</root>
XML
xml2 = <<~XML
<root>
<!-- New comment -->
<element>value2</element>
</root>
XML
# With comments: :ignore and show_diffs: :normative
result = Canon::Comparison.equivalent?(xml1, xml2,
verbose: true,
match: { comments: :ignore },
show_diffs: :normative
)
# Result:
# - equivalent? => false (element value differs)
# - Diff output shows: only the element value change
# - Diff output hides: comment differences (informative)
3. Filtering modes
The show_diffs parameter accepts three values:
3.1. All differences (:all)
Default mode. Shows both normative and informative differences.
Canon::Comparison.equivalent?(doc1, doc2,
verbose: true,
show_diffs: :all # or omit (default)
)
Use when:
-
You want to see every difference
-
Debugging to understand all changes
-
Initial comparison to assess document similarity
3.2. Normative differences only (:normative)
Shows only differences that affect equivalence.
Canon::Comparison.equivalent?(doc1, doc2,
verbose: true,
show_diffs: :normative
)
Use when:
-
Focusing on changes that make documents non-equivalent
-
Hiding informative diffs (e.g., comments when ignored)
-
Clean output for CI/CD pipelines
-
Reviewing semantic changes only
3.3. Informative differences only (:informative)
Shows only differences that don’t affect equivalence.
Canon::Comparison.equivalent?(doc1, doc2,
verbose: true,
show_diffs: :informative
)
Use when:
-
Reviewing non-semantic changes
-
Checking comment differences
-
Auditing metadata changes
-
Verifying ignored dimensions are truly informative
4. Visual distinction: Informative vs normative diffs
Canon visually distinguishes informative from normative diffs using different symbols and colors:
4.1. Normative diffs (affect equivalence)
-
Symbols:
-(red) for deletions,+(green) for additions -
Colors: Red for removed lines, green for added lines
-
Meaning: These differences cause documents to be non-equivalent
4| -| <item>Old</item> # Red - (normative deletion)
| 5+| <item>New</item> # Green + (normative addition)
4.2. Informative diffs (don’t affect equivalence)
-
Symbol:
~(tilde) in cyan/blue -
Color: Cyan (blue) for both removed and added content
-
Meaning: These differences are ignored based on match options
4| ~| <!-- Old comment --> # Cyan ~ (informative)
| 5~| <!-- New comment --> # Cyan ~ (informative)
This visual distinction makes it immediately clear which diffs affect equivalence and which are informational only.
When using the spec_friendly profile, attribute order is informative:
4| ~| <el attr2="b" attr1="a"/> # Cyan ~ (informative)
| 5~| <el attr1="a" attr2="b"/> # Cyan ~ (informative)
The cyan color and ~ symbol indicate this differs does not affect equivalence in the spec_friendly profile.
5. Semantic Diff Report filtering
The show_diffs filter applies to both the line/tree diff output and the
Semantic Diff Report header block. When the Semantic Diff Report is emitted
(whenever verbose: true and differences exist), its two sections are gated
by the same flag:
show_diffs |
NORMATIVE DIFFERENCES section | INFORMATIVE DIFFERENCES section |
|---|---|---|
|
shown |
shown |
|
shown |
hidden |
|
hidden |
shown |
This means that setting show_diffs: :normative (or
cfg.xml.diff.show_diffs = :normative in config) will suppress the
INFORMATIVE DIFFERENCES section from the Semantic Diff Report as well as
from the line diff, giving a consistent, noise-free view of only the
differences that affect equivalence.
Canon::Config.configure do |cfg|
cfg.xml.diff.show_diffs = :normative
end
# The Semantic Diff Report now omits the INFORMATIVE DIFFERENCES section.
# Only the NORMATIVE DIFFERENCES block is rendered.
expect(actual).to be_xml_equivalent_to(expected,
match: { comments: :ignore }
)
6. Usage examples
6.1. Ruby API
require 'canon/comparison'
# Show all differences
result = Canon::Comparison.equivalent?(xml1, xml2,
verbose: true,
match: { comments: :ignore },
show_diffs: :all
)
# Show only normative differences
result = Canon::Comparison.equivalent?(xml1, xml2,
verbose: true,
match: { comments: :ignore },
show_diffs: :normative
)
# Show only informative differences
result = Canon::Comparison.equivalent?(xml1, xml2,
verbose: true,
match: { comments: :ignore },
show_diffs: :informative
)
# Access via DiffFormatter directly
formatter = Canon::DiffFormatter.new(
use_color: true,
mode: :by_object,
show_diffs: :normative
)
output = formatter.format(result, :xml)
6.2. Command-line interface
# Show all differences (default)
$ canon diff file1.xml file2.xml
# Show only normative differences
$ canon diff file1.xml file2.xml --show-diffs normative
# Show only informative differences
$ canon diff file1.xml file2.xml --show-diffs informative
# Combined with match options
$ canon diff file1.xml file2.xml \
--comments ignore \
--show-diffs normative
6.3. RSpec matchers
require 'canon/rspec_matchers'
RSpec.describe 'XML comparison' do
it 'matches equivalent documents' do
# Show all differences on failure
expect(actual).to be_xml_equivalent_to(expected)
.show_diffs(:all)
end
it 'shows only normative differences' do
expect(actual).to be_xml_equivalent_to(expected,
match: { comments: :ignore }
).show_diffs(:normative)
end
it 'shows only informative differences' do
expect(actual).to be_xml_equivalent_to(expected,
match: { comments: :ignore }
).show_diffs(:informative)
end
end
7. Relationship to equivalence
Display filtering does NOT affect equivalence determination.
Equivalence is always based on normative differences only, regardless of the
show_diffs setting.
|
xml1 = "<root><!-- Comment A --><el>value</el></root>"
xml2 = "<root><!-- Comment B --><el>value</el></root>"
# All three produce the same equivalence result
result_all = Canon::Comparison.equivalent?(xml1, xml2,
verbose: true,
match: { comments: :ignore },
show_diffs: :all
)
result_normative = Canon::Comparison.equivalent?(xml1, xml2,
verbose: true,
match: { comments: :ignore },
show_diffs: :normative
)
result_informative = Canon::Comparison.equivalent?(xml1, xml2,
verbose: true,
match: { comments: :ignore },
show_diffs: :informative
)
# All return true (only comment diffs, which are informative)
result_all.equivalent? # => true
result_normative.equivalent? # => true
result_informative.equivalent? # => true
# Only diff output differs:
# - result_all: shows comment diffs
# - result_normative: hides comment diffs
# - result_informative: shows comment diffs
8. How it works
The filtering operates at the display layer:
-
Comparison phase: All differences are detected and classified as normative or informative based on match options
-
Equivalence determination: Only normative differences affect the equivalence result
-
Display phase: The
show_diffsparameter filters which differences appear in formatted output
Input Documents
│
▼
Preprocessing (optional)
│
▼
Semantic Matching
│
▼
Diff Detection & Classification
│
├──► Normative DiffNodes
│
└──► Informative DiffNodes
│
▼
Equivalence Determination
(based on normative diffs only)
│
▼
Display Filtering ◄── show_diffs parameter
(filter which diffs to show)
│
▼
Formatted Output
9. Match dimensions and informativeness
Different match dimension settings affect which diffs are normative vs informative:
| Dimension | Setting | Diff Classification |
|---|---|---|
|
|
Normative (affects equivalence) |
|
|
Informative (doesn’t affect equivalence) |
|
|
Normative |
|
|
Normative (but normalized first) |
|
|
Normative |
|
|
Informative |
|
|
Normative |
|
|
Normative (but normalized first) |
|
|
Normative |
|
|
Informative |
|
|
Normative (JSON/YAML) |
|
|
Informative (JSON/YAML) |
10. Best practices
10.1. In test suites
Use show_diffs: :normative to reduce noise in test failures:
Canon::Config.configure do |config|
config.xml.match.profile = :spec_friendly
config.xml.diff.show_diffs = :normative
end
10.2. In CI/CD pipelines
Use show_diffs: :normative for cleaner output:
#!/bin/bash
canon diff expected.xml actual.xml \
--match-profile spec_friendly \
--show-diffs normative
10.3. During development
Use show_diffs: :all to see everything while debugging:
result = Canon::Comparison.equivalent?(doc1, doc2,
verbose: true,
show_diffs: :all
)
10.4. For auditing
Use show_diffs: :informative to verify ignored dimensions don’t have
unexpected changes:
result = Canon::Comparison.equivalent?(doc1, doc2,
verbose: true,
match: { comments: :ignore },
show_diffs: :informative
)
# Review comment changes that were ignored for equivalence
puts result.differences.count # Number of informative diffs
11. See also
-
Match options - Configure match dimensions
-
Colors and symbols - Understanding diff visualization
-
Diff algorithms - Algorithm-specific behavior
-
Diff classification - Normative vs informative classification