Compare commits
2
Commits
v0.1.0
..
20eef0c0b0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20eef0c0b0
|
||
|
|
af063645c7
|
+1
-1
@@ -8,7 +8,7 @@ This analysis tool allows seeing the wikidata behind articles through the lens o
|
||||
|
||||
authors = ["Raymon Zutekouw <contact@raymon.dev>"]
|
||||
|
||||
repository = "https://codeberg.org/MeltingSilicon/wikipedia-infobox-analyzer"
|
||||
repository = ""
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
keywords = ["wikipedia", "wikidata", "infobox"]
|
||||
|
||||
@@ -31,55 +31,6 @@ 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.
|
||||
@@ -94,7 +45,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 software template on the Dutch wikipedia (the first word means "uses", it can be found here: https://nl.wikipedia.org/wiki/Sjabloon:Infobox_software):
|
||||
As an example, this is the case on the following template on the Dutch wikipedia (the first word means "uses"):
|
||||
|
||||
``` text
|
||||
{{Gebruikt Wikidata|P18|P154|P170|P178|P275|P277|P306|P348|P400|P548|P571|P577|P856|P1324|P2096}}
|
||||
|
||||
+21
-65
@@ -5,72 +5,34 @@ pub mod wikipedia_infobox_analyzer {
|
||||
use itertools::Itertools;
|
||||
|
||||
/// Looks for a used template that does lists wikidata properties listing
|
||||
pub fn extract_used_properties_from_template(template: String) -> Vec<u64> {
|
||||
pub fn extract_used_properties_from_template(template: String) -> Vec<String> {
|
||||
let mut lines = template.lines();
|
||||
let used = lines
|
||||
.find(|line| line.starts_with("{{") && line.contains("Wikidata|"))
|
||||
.expect("Template should have a line declaring which properties are used");
|
||||
|
||||
// The properties are listed inside the template with their number: P1|P2|P...
|
||||
let re = Regex::new(r"P(\d+)").unwrap();
|
||||
let re = Regex::new(r"P\d+").unwrap();
|
||||
|
||||
// Find all matches and collect the properties into vector
|
||||
re.captures_iter(used)
|
||||
.map(|m| m[1].parse().unwrap())
|
||||
re.find_iter(used)
|
||||
.map(|m| m.as_str().to_owned())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Creates an ascii infobox out of the properties
|
||||
pub fn format_infobox_from_used_properties(name: String, qid: String, properties_template: Vec<u64>, properties_item: Vec<u64>, ) -> String {
|
||||
pub fn format_infobox_from_used_properties(name: String, properties: Vec<u64>) -> String {
|
||||
let mut ascii_table = AsciiTable::default();
|
||||
ascii_table.set_max_width(80);
|
||||
ascii_table.set_max_width(26);
|
||||
ascii_table
|
||||
.column(0)
|
||||
.set_header("Infobox requires")
|
||||
.set_header(name)
|
||||
.set_align(Align::Left);
|
||||
|
||||
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();
|
||||
let data: Vec<Vec<String>> = properties.iter().map(|v| vec![format!("P{v}")]).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!("
|
||||
@@ -154,9 +116,9 @@ mod tests {
|
||||
assert_eq!(
|
||||
extract_used_properties_from_template(contents),
|
||||
vec![
|
||||
18, 154, 1128, 4103, 2139, 2295, 2226, 856, 169,
|
||||
1448, 159, 749, 355, 17, 1056, 452, 576, 112, 127,
|
||||
856, 2096
|
||||
"P18", "P154", "P1128", "P4103", "P2139", "P2295", "P2226", "P856", "P169",
|
||||
"P1448", "P159", "P749", "P355", "P17", "P1056", "P452", "P576", "P112", "P127",
|
||||
"P856", "P2096"
|
||||
]
|
||||
);
|
||||
|
||||
@@ -166,8 +128,8 @@ mod tests {
|
||||
assert_eq!(
|
||||
extract_used_properties_from_template(contents),
|
||||
vec![
|
||||
18, 154, 170, 178, 275, 277, 306, 348, 400, 548,
|
||||
571, 577, 856, 1324, 2096
|
||||
"P18", "P154", "P170", "P178", "P275", "P277", "P306", "P348", "P400", "P548",
|
||||
"P571", "P577", "P856", "P1324", "P2096"
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -177,22 +139,16 @@ mod tests {
|
||||
assert_eq!(
|
||||
format_infobox_from_used_properties(
|
||||
"Earth".to_string(),
|
||||
"Q2".to_string(),
|
||||
vec![18, 170, 571],
|
||||
vec![18, 31, 138, 170, 361, 571]
|
||||
vec![31, 361, 571]
|
||||
),
|
||||
|
||||
concat![
|
||||
"┌──────────────────┬─────────────────────┐\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",
|
||||
"┌───────┐\n",
|
||||
"│ Earth │\n", // item identifier: Q2
|
||||
"├───────┤\n",
|
||||
"│ P31 │\n", // property: instance of
|
||||
"│ P361 │\n", // property: part of
|
||||
"│ P571 │\n", // property: inception
|
||||
"└───────┘\n"
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
+5
-10
@@ -17,20 +17,15 @@ 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_item = fetch_properties_for_wiki_item(qid);
|
||||
let table = format_infobox_from_used_properties(
|
||||
title.clone(),
|
||||
format!("Q{qid}"),
|
||||
properties_template,
|
||||
properties_item,
|
||||
);
|
||||
let properties = fetch_properties_for_wiki_item(qid);
|
||||
let table = format_infobox_from_used_properties(title.clone(), properties);
|
||||
|
||||
// Output of the program
|
||||
println!("Qid: {qid}");
|
||||
println!("Template file exists");
|
||||
println!("{table}");
|
||||
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user