3 Commits
Author SHA1 Message Date
raymon 8937c5677f Give an example of applying a different template 2025-08-04 12:34:40 +02:00
raymon ddc8caa684 Add code repo to cargo file 2025-08-04 12:17:30 +02:00
raymon d938106f84 Show the property columns side by side
- infobox requirements
- wikidata entries
2025-08-04 12:12:33 +02:00
4 changed files with 117 additions and 19 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ This analysis tool allows seeing the wikidata behind articles through the lens o
authors = ["Raymon Zutekouw <contact@raymon.dev>"]
repository = ""
repository = "https://codeberg.org/MeltingSilicon/wikipedia-infobox-analyzer"
license = "MIT OR Apache-2.0"
keywords = ["wikipedia", "wikidata", "infobox"]
+50 -1
View File
@@ -31,6 +31,55 @@ By default, the tool assumes that you are looking for tools on the English wikip
Make sure the passed title matches the article title, and the tool should be able to find the wikidata entry.
The next section will go over what these infobox templates files are, where you can find them on wikipedia, and how you can customize them locally for your wikidata analysis.
### Interpretation of output
The left column of the table first lists all the properties that the infobox requires.
The right column will display the same property name if it is present in wikidata.
If it is not present, the right column will be blank.
Remaining properties in wikidata that are not required by the infobox are trailed in the right column.
``` markdown
┌──────────────────┬─────────────────────┐
│ Infobox requires │ Wikidata Earth (Q2) │
├──────────────────┼─────────────────────┤
│ P18 │ P18 │ // property: image
│ P170 │ P170 │ // property: creator
│ P571 │ P571 │ // property: inception
│ │ P31 │ // property: instance of
│ │ P138 │ // property: inception
│ │ P361 │ // property: part of
│ │ .... │
└──────────────────┴─────────────────────┘
```
This (shortened) example is complete, but if we were to try a different infobox template on the earth entry you can see that it is not a good fit.
To demonstrate, we can apply the software template to the earth entry:
``` markdown
┌──────────────────┬─────────────────────┐
│ Infobox requires │ Wikidata Earth (Q2) │
├──────────────────┼─────────────────────┤
│ P18 │ P18 │ // property: image
│ P154 │ │
│ P170 │ P170 │ // property: creator
│ P178 │ │
│ P275 │ │
│ P277 │ │
│ P306 │ │
│ P348 │ │
│ P400 │ │
│ P548 │ │
│ P571 │ P571 │ // property: inception
│ P577 │ │
│ P856 │ │
│ P1324 │ │
│ P2096 │ │
│ │ P10 │
│ │ P31 │
│ │ P138 │
│ │ .... │
└──────────────────┴─────────────────────┘
```
## Templates
The wikipedia sites vary a lot when it comes to templates across the different languages.
The goal of this tool is to be universal, but these templates have not been standardized as far as I am aware.
@@ -45,7 +94,7 @@ Then you can add the following line to that file locally:
The program ignores what you put at the `...`.
It permits templates that include a listing of wikidata entries for their templates.
As an example, this is the case on the following template on the Dutch wikipedia (the first word means "uses"):
As an example, this is the case on the following software template on the Dutch wikipedia (the first word means "uses", it can be found here: https://nl.wikipedia.org/wiki/Sjabloon:Infobox_software):
``` text
{{Gebruikt Wikidata|P18|P154|P170|P178|P275|P277|P306|P348|P400|P548|P571|P577|P856|P1324|P2096}}
+56 -12
View File
@@ -21,18 +21,56 @@ pub mod wikipedia_infobox_analyzer {
}
/// Creates an ascii infobox out of the properties
pub fn format_infobox_from_used_properties(name: String, properties: Vec<u64>) -> String {
pub fn format_infobox_from_used_properties(name: String, qid: String, properties_template: Vec<u64>, properties_item: Vec<u64>, ) -> String {
let mut ascii_table = AsciiTable::default();
ascii_table.set_max_width(26);
ascii_table.set_max_width(80);
ascii_table
.column(0)
.set_header(name)
.set_header("Infobox requires")
.set_align(Align::Left);
let data: Vec<Vec<String>> = properties.iter().map(|v| vec![format!("P{v}")]).collect();
ascii_table
.column(1)
.set_header(format!("Wikidata {name} ({qid})"))
.set_align(Align::Left);
// Display the property columns as a table
let data: Vec<Vec<String>> = join_columns(&properties_template, &properties_item)
.iter()
.map(|&m| {
let (v1, v2) = m;
vec![ v1.map_or("".to_owned(), |v| format!("P{v}").to_owned())
, v2.map_or("".to_owned(), |v| format!("P{v}").to_owned())]
}
).collect();
ascii_table.format(data)
}
/// Properties will be displayed in the right column if they are in the list for that column
/// All items in the left columns will be displayed
/// The remaining items in the right columns not in the left columns will trail in the right column
/// ┌───────┬───────┐
/// │ 1 │ 1 │
/// │ 3 │ │
/// │ │ 2 │
/// │ │ 4 │
/// └───────┴───────┘
/// So for example, [1, 3] and [1, 2, 4] become [1, 2, 3, 4], as shown above
fn join_columns<T: Copy + Eq>(vec1: &[T], vec2: &[T]) -> Vec<(Option<T>, Option<T>)> {
vec1.iter()
.flat_map(|n1| {
if let Some(&n2) = vec2.iter().find(|&x| x == n1) {
std::iter::once((Some(*n1), Some(n2)))
} else {
std::iter::once((Some(*n1), None))
}
})
.chain(vec2.iter()
.filter(|&n2| !vec1.contains(n2))
.map(|n2| (None, Some(*n2))))
.collect()
}
/// Fetches the wikidata label for the wiki property
pub async fn fetch_name_for_wiki_property(pid: u64) -> String {
let query = format!("
@@ -139,16 +177,22 @@ mod tests {
assert_eq!(
format_infobox_from_used_properties(
"Earth".to_string(),
vec![31, 361, 571]
"Q2".to_string(),
vec![18, 170, 571],
vec![18, 31, 138, 170, 361, 571]
),
concat![
"┌───────┐\n",
"│ Earth │\n", // item identifier: Q2
"├───────┤\n",
"│ P31 │\n", // property: instance of
"│ P361 │\n", // property: part of
"│ P571 │\n", // property: inception
"└───────┘\n"
"┌──────────────────┬─────────────────────┐\n",
"│ Infobox requires │ Wikidata Earth (Q2) │\n",
"├──────────────────┼─────────────────────┤\n",
"│ P18 │ P18 │\n", // property: image
"│ P170 │ P170 │\n", // property: creator
"│ P571 │ P571 │\n", // property: inception
"│ │ P31 │\n", // property: instance of
"│ │ P138 │\n", // property: inception
"│ │ P361 │\n", // property: part of
"└──────────────────┴─────────────────────┘\n",
]
);
}
+10 -5
View File
@@ -17,15 +17,20 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Input to the program
let title = args.wikipedia_article_title;
let language = args.wikipedia_language_code;
let _template = std::fs::read_to_string(&args.infobox_template_file)?;
let template = std::fs::read_to_string(&args.infobox_template_file)?;
let qid = fetch_wiki_item_by_article_title(title.clone(), language.clone());
let properties_template = extract_used_properties_from_template(template);
let properties = fetch_properties_for_wiki_item(qid);
let table = format_infobox_from_used_properties(title.clone(), properties);
let properties_item = fetch_properties_for_wiki_item(qid);
let table = format_infobox_from_used_properties(
title.clone(),
format!("Q{qid}"),
properties_template,
properties_item,
);
println!("Qid: {qid}");
println!("Template file exists");
// Output of the program
println!("{table}");
Ok(())