diff --git a/src/law.rs b/src/law/mod.rs similarity index 91% rename from src/law.rs rename to src/law/mod.rs index 1712685..4e0053f 100644 --- a/src/law.rs +++ b/src/law/mod.rs @@ -9,6 +9,13 @@ use std::{ use crate::{overview, par}; +use self::responsible::{ + contains, contains_at_start, contains_without_unter, starts_with_letter, starts_with_number, + starts_with_roman_number, starts_with_uppercaseletter, +}; + +mod responsible; + #[derive(Debug, Serialize, Deserialize, PartialEq)] pub(crate) struct Law { name: String, //ABGB, UrhG @@ -102,50 +109,6 @@ impl From for HeadingContent { } } -pub(crate) fn contains_without_unter(classifier_name: &str, instance_name: &str) -> bool { - instance_name - .to_lowercase() - .contains(&classifier_name.to_lowercase()) - && !instance_name.to_lowercase().contains("unter") -} - -pub(crate) fn contains(classifier_name: &str, instance_name: &str) -> bool { - instance_name - .to_lowercase() - .contains(&classifier_name.to_lowercase()) -} - -fn starts_with_roman_number(_: &str, s: &str) -> bool { - // Define the prefixes for Roman numerals. - let roman_prefixes = [ - "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", - "XV", "XVI", "XVII", "XVIII", "XIX", "XX", - ]; - - // Check if the string starts with one of the Roman numeral prefixes followed by a period. - roman_prefixes - .iter() - .any(|&prefix| s.starts_with(&(prefix.to_string() + "."))) -} - -fn contains_at_start(_classifier_name: &str, instance_name: &str) -> bool { - !instance_name.is_empty() && instance_name.starts_with('@') -} - -fn starts_with_number(_classifier_name: &str, instance_name: &str) -> bool { - matches!(instance_name.trim().as_bytes().first(), Some(c) if c.is_ascii_digit()) -} - -fn starts_with_letter(_classifier_name: &str, instance_name: &str) -> bool { - instance_name.starts_with(|c: char| c.is_ascii_lowercase()) - && (instance_name.chars().nth(1) == Some('.') || instance_name.chars().nth(1) == Some(')')) -} - -fn starts_with_uppercaseletter(_classifier_name: &str, instance_name: &str) -> bool { - instance_name.starts_with(|c: char| c.is_ascii_uppercase()) - && (instance_name.chars().nth(1) == Some('.') || instance_name.chars().nth(1) == Some(')')) -} - /// Is used to generate a law struct. It's organized mainly by classifier. #[derive(Debug)] pub(crate) struct LawBuilder { @@ -259,6 +222,11 @@ impl LawBuilder { classifiers.push(Classifier::new("Hauptstück", Arc::new(&contains)).root()); classifiers.push(Classifier::new("Abschnitt", Arc::new(&contains))); + } else if name == "StGB" { + law_id = Some(10002296); + + classifiers.push(Classifier::new("Teil", Arc::new(&contains)).root()); + classifiers.push(Classifier::new("Abschnitt", Arc::new(&contains))); } let mut builder = Self { diff --git a/src/law/responsible.rs b/src/law/responsible.rs new file mode 100644 index 0000000..bef0af0 --- /dev/null +++ b/src/law/responsible.rs @@ -0,0 +1,43 @@ +pub(crate) fn contains_without_unter(classifier_name: &str, instance_name: &str) -> bool { + instance_name + .to_lowercase() + .contains(&classifier_name.to_lowercase()) + && !instance_name.to_lowercase().contains("unter") +} + +pub(crate) fn contains(classifier_name: &str, instance_name: &str) -> bool { + instance_name + .to_lowercase() + .contains(&classifier_name.to_lowercase()) +} + +pub(crate) fn starts_with_roman_number(_: &str, s: &str) -> bool { + // Define the prefixes for Roman numerals. + let roman_prefixes = [ + "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", + "XV", "XVI", "XVII", "XVIII", "XIX", "XX", + ]; + + // Check if the string starts with one of the Roman numeral prefixes followed by a period. + roman_prefixes + .iter() + .any(|&prefix| s.starts_with(&(prefix.to_string() + "."))) +} + +pub(crate) fn contains_at_start(_classifier_name: &str, instance_name: &str) -> bool { + !instance_name.is_empty() && instance_name.starts_with('@') +} + +pub(crate) fn starts_with_number(_classifier_name: &str, instance_name: &str) -> bool { + matches!(instance_name.trim().as_bytes().first(), Some(c) if c.is_ascii_digit()) +} + +pub(crate) fn starts_with_letter(_classifier_name: &str, instance_name: &str) -> bool { + instance_name.starts_with(|c: char| c.is_ascii_lowercase()) + && (instance_name.chars().nth(1) == Some('.') || instance_name.chars().nth(1) == Some(')')) +} + +pub(crate) fn starts_with_uppercaseletter(_classifier_name: &str, instance_name: &str) -> bool { + instance_name.starts_with(|c: char| c.is_ascii_uppercase()) + && (instance_name.chars().nth(1) == Some('.') || instance_name.chars().nth(1) == Some(')')) +} diff --git a/src/main.rs b/src/main.rs index 805ff45..ec16529 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,48 +1,13 @@ -use std::io; - use law::LawBuilder; mod law; mod overview; mod par; -#[derive(Debug)] -pub struct Error { - msg: String, -} - -impl From for Error { - fn from(value: ureq::Error) -> Self { - Self { - msg: value.to_string(), - } - } -} -impl From for Error { - fn from(value: io::Error) -> Self { - Self { - msg: value.to_string(), - } - } -} -impl From for Error { - fn from(value: serde_json::Error) -> Self { - Self { - msg: value.to_string(), - } - } -} -impl From for Error { - fn from(value: roxmltree::Error) -> Self { - Self { - msg: value.to_string(), - } - } -} - +mod misc; fn main() { env_logger::init(); - let law = LawBuilder::new("KSchG"); + let law = LawBuilder::new("StGB"); law.to_md(); } diff --git a/src/misc.rs b/src/misc.rs new file mode 100644 index 0000000..815f205 --- /dev/null +++ b/src/misc.rs @@ -0,0 +1,35 @@ +use std::io; + +#[derive(Debug)] +pub struct Error { + msg: String, +} + +impl From for Error { + fn from(value: ureq::Error) -> Self { + Self { + msg: value.to_string(), + } + } +} +impl From for Error { + fn from(value: io::Error) -> Self { + Self { + msg: value.to_string(), + } + } +} +impl From for Error { + fn from(value: serde_json::Error) -> Self { + Self { + msg: value.to_string(), + } + } +} +impl From for Error { + fn from(value: roxmltree::Error) -> Self { + Self { + msg: value.to_string(), + } + } +} diff --git a/src/overview/mod.rs b/src/overview/mod.rs index b4c10ba..de1b4df 100644 --- a/src/overview/mod.rs +++ b/src/overview/mod.rs @@ -5,7 +5,7 @@ use log::info; use serde::Deserialize; use time::{format_description, OffsetDateTime}; -use crate::{overview::parser::OgdSearchResult, Error}; +use crate::{misc::Error, overview::parser::OgdSearchResult}; /// Returns the current date in YYYY-MM-DD format. Needed for RIS API query to get current version of the overview. fn current_date() -> String { diff --git a/src/par/mod.rs b/src/par/mod.rs index 69c057b..8d8cc14 100644 --- a/src/par/mod.rs +++ b/src/par/mod.rs @@ -2,7 +2,7 @@ mod parser; use log::{debug, info}; -use crate::{law::LawBuilder, par::parser::Risdok, Error}; +use crate::{law::LawBuilder, misc::Error, par::parser::Risdok}; fn fetch_page(url: &str) -> Result { Ok(ureq::get(url).call()?.into_string()?) @@ -23,6 +23,33 @@ pub(crate) fn parse_from_str(xml: &str, builder: &mut LawBuilder) -> Result(2) Einer Rundfunksendung steht es gleich, wenn ein Werk von einer im In- oder im Ausland gelegenen Stelle aus der Öffentlichkeit im Inland, ähnlich wie durch Rundfunk, aber mit Hilfe von Leitungen wahrnehmbar gemacht wird."#, ); + let xml = xml.replace( + // in § 17 (2) + r#"(3) Die Verjährungsfrist beträgtzwanzig Jahre,wenn die Handlung zwar nicht mit lebenslanger Freiheitsstrafe, aber mit mehr als zehnjähriger Freiheitsstrafe bedroht ist;zehn Jahre,wenn die Handlung mit mehr als fünfjähriger, aber höchstens zehnjähriger Freiheitsstrafe bedroht ist;fünf Jahre,wenn die Handlung mit mehr als einjähriger, aber höchstens fünfjähriger Freiheitsstrafe bedroht ist;drei Jahre,wenn die Handlung mit mehr als sechsmonatiger, aber höchstens einjähriger Freiheitsstrafe bedroht ist;ein Jahr,wenn die Handlung mit nicht mehr als sechsmonatiger Freiheitsstrafe oder nur mit Geldstrafe bedroht ist."#, + r#"(3) Die Verjährungsfrist beträgt zwanzig Jahre, wenn die Handlung zwar nicht mit lebenslanger Freiheitsstrafe, aber mit mehr als zehnjähriger Freiheitsstrafe bedroht ist; zehn Jahre, wenn die Handlung mit mehr als fünfjähriger, aber höchstens zehnjähriger Freiheitsstrafe bedroht ist; fünf Jahre, wenn die Handlung mit mehr als einjähriger, aber höchstens fünfjähriger Freiheitsstrafe bedroht ist; drei Jahre, wenn die Handlung mit mehr als sechsmonatiger, aber höchstens einjähriger Freiheitsstrafe bedroht ist; ein Jahr, wenn die Handlung mit nicht mehr als sechsmonatiger Freiheitsstrafe oder nur mit Geldstrafe bedroht ist."#, + ); + + let xml = xml.replace( + r#"(3) Die Frist beträgtfünfzehn Jahre,wenn auf Freiheitsstrafe von mehr als einem Jahr, aber nicht mehr als zehn Jahren erkannt worden ist;zehn Jahre,wenn auf Freiheitsstrafe von mehr als drei Monaten, aber nicht mehr als einem Jahr oder auf eine Geldstrafe unter Festsetzung einer Ersatzfreiheitsstrafe von mehr als drei Monaten erkannt worden ist;fünf Jahrein allen übrigen Fällen."#, + r#"(3) Die Frist beträgt fünfzehn Jahre, wenn auf Freiheitsstrafe von mehr als einem Jahr, aber nicht mehr als zehn Jahren erkannt worden ist; zehn Jahre, wenn auf Freiheitsstrafe von mehr als drei Monaten, aber nicht mehr als einem Jahr oder auf eine Geldstrafe unter Festsetzung einer Ersatzfreiheitsstrafe von mehr als drei Monaten erkannt worden ist; fünf Jahre in allen übrigen Fällen."#, + ); + + let xml = xml.replace( + r#"Erster Abschnitt"#, + r#"Erster Abschnitt"#, + ); // StGB + + let xml = xml.replace(r#""#, r#""#); // StGB... + + let xml = xml.replace( + r#"Strafbare Handlungen gegen Leib und Leben"#, + r#"Strafbare Handlungen gegen Leib und Leben"#, + ); // StGB + let xml = xml.replace( + r#"Allgemeine Bestimmungen"#, + r#"Allgemeine Bestimmungen"#, + ); // StGB + let xml = xml.replace( r#"1. Verwertungsrechte."#, r#"1. Verwertungsrechte."#, diff --git a/src/par/parser.rs b/src/par/parser.rs index 9923140..882e514 100644 --- a/src/par/parser.rs +++ b/src/par/parser.rs @@ -2,7 +2,7 @@ use roxmltree::Node; use crate::{ law::{Content, LawBuilder}, - Error, + misc::Error, }; #[derive(Debug, PartialEq)] @@ -489,11 +489,11 @@ impl Absatz { n.tag_name().name() == "absatz" } pub(crate) fn test_with_typ(n: &Node, typ: &str) -> bool { - n.tag_name().name() == "absatz" && n.attribute("typ") == Some(typ) + Self::test(n) && n.attribute("typ") == Some(typ) } pub(crate) fn parse(n: Node) -> Self { - assert!(n.tag_name().name() == "absatz"); + assert!(Self::test(&n)); if let Some(text) = n.text() { Self {