diff --git a/index.html b/index.html
new file mode 100644
index 0000000..1b09928
--- /dev/null
+++ b/index.html
@@ -0,0 +1,24 @@
+
+
+
+
+ Project Dependencies
+
+
+ Project Dependencies
| Group ID | Artifact ID | Version |
|---|
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index f53b3a8..d985f84 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,8 @@
use std::path::PathBuf;
-use std::env;
+use std::{env, fs};
use undeepend::maven::project::parse_project;
use undeepend::maven::reporter::report;
+use undeepend::maven::settings::get_settings;
fn main() {
let args = std::env::args().collect::>();
@@ -11,15 +12,12 @@ fn main() {
PathBuf::from(&args[1])
};
let project = parse_project(&dir).unwrap();
- // //
- // // fs::write(
- // // PathBuf::from("index.html"),
- // // project.generate_dependency_html(),
- // // )
- // // .unwrap();
- //
- // report(&project);
- for pom in project.iter(){
- println!("{:?}", pom);
- }
+ get_settings().unwrap();
+ fs::write(
+ PathBuf::from("index.html"),
+ project.generate_dependency_html(),
+ )
+ .unwrap();
+
+ report(&project);
}
diff --git a/src/maven/mod.rs b/src/maven/mod.rs
index aed2c31..bbb0a31 100644
--- a/src/maven/mod.rs
+++ b/src/maven/mod.rs
@@ -1,5 +1,14 @@
+use std::{env, sync::LazyLock};
+
pub mod metadata;
pub mod pom;
pub mod pom_parser;
pub mod project;
-pub mod reporter;
\ No newline at end of file
+pub mod reporter;
+pub mod settings;
+
+pub const HOME: LazyLock = LazyLock::new(|| env::var("HOME").unwrap());
+pub const MAVEN_HOME: LazyLock =
+ LazyLock::new(|| env::var("MAVEN_HOME").unwrap_or("".to_string()));
+pub const CUSTOM_SETTINGS_LOCATION: LazyLock =
+ LazyLock::new(|| env::var("SETTINGS_PATH").unwrap_or("".to_string()));
diff --git a/src/maven/pom.rs b/src/maven/pom.rs
index 95a929e..ae9e87a 100644
--- a/src/maven/pom.rs
+++ b/src/maven/pom.rs
@@ -1,13 +1,9 @@
use std::collections::HashMap;
-use std::env;
use std::fmt::Display;
use std::path::PathBuf;
-use std::sync::LazyLock;
/// the maven object model
-const HOME: LazyLock = LazyLock::new(|| env::var("HOME").unwrap());
-
#[derive(PartialEq, Debug)]
pub struct Pom {
pub parent: Option,
@@ -80,13 +76,19 @@ impl Dependency {
use std::fmt;
+use crate::maven::HOME;
+
impl Display for Dependency {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let version = self.version.clone().unwrap_or_else(|| "latest".to_string());
write!(
f,
"{}/{}/{}/{}-{}",
- self.group_id.replace(".","/"), self.artifact_id, version, self.artifact_id, version
+ self.group_id.replace(".", "/"),
+ self.artifact_id,
+ version,
+ self.artifact_id,
+ version
)
}
}
diff --git a/src/maven/pom_parser.rs b/src/maven/pom_parser.rs
index 7f105b9..f3ea27a 100644
--- a/src/maven/pom_parser.rs
+++ b/src/maven/pom_parser.rs
@@ -7,7 +7,7 @@ use std::path::PathBuf;
/// parse the pom.xml into a Pom object (struct)
pub fn get_pom(home_dir: PathBuf, xml: impl Into) -> Result {
let mut group_id = None;
- let mut artefact_id = None;
+ let mut artifact_id = None;
let mut parent = None;
let mut version = None;
let mut name = None;
@@ -21,7 +21,7 @@ pub fn get_pom(home_dir: PathBuf, xml: impl Into) -> Result group_id = child.text,
- "artifactId" => artefact_id = child.text,
+ "artifactId" => artifact_id = child.text,
"parent" => parent = Some(get_parent(&child)),
"version" => version = child.text,
"name" => name = child.text,
@@ -37,7 +37,7 @@ pub fn get_pom(home_dir: PathBuf, xml: impl Into) -> Result Vec {
fn get_dependency(element: Node) -> Dependency {
let mut grouo_id = None;
- let mut artefact_id = None;
+ let mut artifact_id = None;
let mut version = None;
for node in element.children {
match node.name.as_str() {
"groupId" => grouo_id = node.text,
- "artifactId" => artefact_id = node.text,
+ "artifactId" => artifact_id = node.text,
"version" => version = node.text,
_ => {}
}
}
Dependency {
group_id: grouo_id.unwrap(),
- artifact_id: artefact_id.unwrap(),
+ artifact_id: artifact_id.unwrap(),
version,
}
}
@@ -136,19 +136,19 @@ fn get_developer(element: Node) -> Developer {
fn get_parent(element: &Node) -> Parent {
let mut group_id = None;
- let mut artefact_id = None;
+ let mut artifact_id = None;
let mut version = None;
for child in &element.children {
match child.name.as_str() {
"groupId" => group_id = child.text.clone(),
- "artefactId" => artefact_id = child.text.clone(),
+ "artifactId" => artifact_id = child.text.clone(),
"version" => version = child.text.clone(),
_ => {}
}
}
Parent {
group_id: group_id.unwrap(),
- artifact_id: artefact_id.unwrap(),
+ artifact_id: artifact_id.unwrap(),
version: version.unwrap(),
}
}
diff --git a/src/maven/project.rs b/src/maven/project.rs
index 3937e60..e55e10d 100644
--- a/src/maven/project.rs
+++ b/src/maven/project.rs
@@ -196,15 +196,14 @@ impl Project {
get_project_pom(&self.root, group_id, artifact_id)
}
- pub fn iter(&self) -> PomIterator{
- PomIterator{
+ pub fn iter<'a>(&'a self) -> PomIterator<'a> {
+ PomIterator {
project: self,
idx: 0,
}
}
}
-
pub struct PomIterator<'a> {
project: &'a Project,
idx: usize,
@@ -212,10 +211,7 @@ pub struct PomIterator<'a> {
impl<'a> PomIterator<'a> {
pub fn new(project: &'a Project) -> Self {
- PomIterator {
- project,
- idx: 0,
- }
+ PomIterator { project, idx: 0 }
}
}
@@ -231,4 +227,4 @@ impl<'a> Iterator for PomIterator<'a> {
None
}
}
-}
\ No newline at end of file
+}
diff --git a/src/maven/reporter.rs b/src/maven/reporter.rs
index bb2d73a..0515409 100644
--- a/src/maven/reporter.rs
+++ b/src/maven/reporter.rs
@@ -3,7 +3,7 @@ use crate::maven::project::Project;
use regex::Regex;
use std::collections::HashSet;
use std::fs::File;
-use std::io::{BufWriter, Read, Write};
+use std::io::{BufWriter, Write};
use std::path::{Path, PathBuf};
use std::sync::LazyLock;
use zip::ZipArchive;
@@ -11,6 +11,7 @@ use zip::ZipArchive;
static CLASS_EXPR: LazyLock = LazyLock::new(|| Regex::new(r"(.+)/.+\.class").unwrap());
const MAVEN_CENTRAL: &str = "https://repo1.maven.org/maven2/";
+// TODO should not be downloading dependencies
pub fn report(project: &Project) {
let pom = &project.root;
for dep in &project.get_dependencies(pom) {
@@ -52,14 +53,14 @@ fn download(dep: &Dependency) -> Result<(), String> {
let url = format!("{}{}.jar", MAVEN_CENTRAL, dep);
let client = Client::builder()
- .timeout(std::time::Duration::from_secs(30)) // Ruime timeout instellen
+ .timeout(std::time::Duration::from_secs(30))
.build()
.map_err(|e| e.to_string())?;
println!("Downloading {}", &url);
let response = client
.get(&url)
- .header("User-Agent", "Maven/1.0") // Goede practice om een User-Agent te sturen
+ .header("User-Agent", "Maven/1.0")
.send()
.map_err(|e| e.to_string())?;
if response.status().is_success() {
diff --git a/src/maven/settings.rs b/src/maven/settings.rs
new file mode 100644
index 0000000..9e140df
--- /dev/null
+++ b/src/maven/settings.rs
@@ -0,0 +1,523 @@
+use std::{fs, path::PathBuf, str::FromStr};
+
+use crate::{
+ maven::{CUSTOM_SETTINGS_LOCATION, HOME, MAVEN_HOME},
+ xml::dom_parser::{Node, get_document},
+};
+
+pub fn get_settings() -> Result {
+ let mut local_repository = None;
+ let mut interactive_mode = true;
+ let mut use_plugin_registry = false;
+ let mut offline = false;
+ let mut proxies = vec![];
+ let mut servers = vec![];
+ let mut mirrors = vec![];
+ let mut profiles = vec![];
+ let mut active_profiles = vec![];
+ let mut plugin_groups = vec![];
+
+ let settings_path = get_settings_path();
+ let settings_file = fs::read_to_string(settings_path?).map_err(|e| e.to_string())?;
+
+ for child in get_document(settings_file)
+ .map_err(|err| err.to_string())?
+ .root
+ .children
+ {
+ match child.name.as_str() {
+ "localRepository" => local_repository = child.text,
+ "interactiveMode" => interactive_mode = child.text.map(|b| b == "true").unwrap_or(true),
+ "usePluginRegistry" => {
+ use_plugin_registry = child.text.map(|b| b == "true").unwrap_or(false)
+ }
+ "offline" => offline = child.text.map(|b| b == "true").unwrap_or(false),
+ "proxies" => proxies = get_proxies(child),
+ "servers" => servers = get_servers(child),
+ "mirrors" => mirrors = get_mirrors(child),
+ "profiles" => profiles = get_profiles(child),
+ "activeProfiles" => active_profiles = get_active_profiles(child),
+ "pluginGroups" => plugin_groups = get_plugin_groups(child),
+ _ => {}
+ };
+ }
+
+ Ok(Settings {
+ local_repository,
+ interactive_mode,
+ use_plugin_registry,
+ offline,
+ proxies,
+ servers,
+ mirrors,
+ profiles,
+ active_profiles,
+ plugin_groups,
+ })
+}
+
+fn get_proxies(element: Node) -> Vec {
+ let mut proxies = vec![];
+ for child in element.children {
+ proxies.push(get_proxy(child));
+ }
+ proxies
+}
+
+fn get_active_profiles(element: Node) -> Vec {
+ let mut active_profiles = vec![];
+ for child in element.children {
+ if let Some(active_profile) = child.text {
+ active_profiles.push(active_profile);
+ }
+ }
+ active_profiles
+}
+
+fn get_plugin_groups(element: Node) -> Vec {
+ let mut plugin_groups = vec![];
+ for child in element.children {
+ if let Some(plugin_group) = child.text {
+ plugin_groups.push(plugin_group);
+ }
+ }
+ plugin_groups
+}
+
+fn get_servers(servers_element: Node) -> Vec {
+ let mut servers = vec![];
+ for server_element in servers_element.children {
+ servers.push(get_server(server_element));
+ }
+ servers
+}
+
+fn get_mirrors(mirrors_element: Node) -> Vec {
+ let mut mirrors = vec![];
+ for mirror_element in mirrors_element.children {
+ mirrors.push(get_mirror(mirror_element));
+ }
+ mirrors
+}
+
+fn get_profiles(profiles_element: Node) -> Vec {
+ let mut profiles = vec![];
+ for mirror_element in profiles_element.children {
+ profiles.push(get_profile(mirror_element));
+ }
+ profiles
+}
+
+fn get_server(server_element: Node) -> Server {
+ let mut id = None;
+ let mut username = None;
+ let mut password = None;
+ let mut private_key = None;
+ let mut passphrase = None;
+ let mut file_permissions = None;
+ let mut directory_permissions = None;
+ let mut configuration = None;
+ for child in server_element.children {
+ match child.name.as_str() {
+ "id" => id = child.text,
+ "username" => username = child.text,
+ "password" => password = child.text,
+ "private_key" => private_key = child.text,
+ "passphrase" => passphrase = child.text,
+ "filePermissions" => file_permissions = child.text,
+ "directoryPermissions" => directory_permissions = child.text,
+ "configuration" => configuration = Some(child),
+ _ => {}
+ }
+ }
+ Server {
+ id,
+ username,
+ password,
+ private_key,
+ passphrase,
+ file_permissions,
+ directory_permissions,
+ configuration,
+ }
+}
+
+fn get_proxy(element: Node) -> Proxy {
+ let mut active = false;
+ let mut protocol = "http".to_owned();
+ let mut username = None;
+ let mut password = None;
+ let mut port: usize = 8080;
+ let mut host = None;
+ let mut non_proxy_hosts = None;
+ let mut id = None;
+
+ for child in element.children {
+ match child.name.as_str() {
+ "active" => active = child.text.map(|b| b == "true").unwrap_or(false),
+ "protocol" => protocol = child.text.unwrap_or("http".to_owned()),
+ "username" => username = child.text,
+ "password" => password = child.text,
+ "port" => {
+ port = child
+ .text
+ .map(|i| {
+ usize::from_str(&i).expect(&format!("Illegal value for port: '{}'", i))
+ })
+ .unwrap_or(8080)
+ }
+ "host" => host = child.text,
+ "non_proxy_hosts" => non_proxy_hosts = child.text,
+ "id" => id = child.text,
+ _ => {}
+ }
+ }
+
+ Proxy {
+ active,
+ protocol,
+ username,
+ password,
+ port,
+ host,
+ non_proxy_hosts,
+ id,
+ }
+}
+
+fn get_mirror(mirror_element: Node) -> Mirror {
+ let mut id = None;
+ let mut mirror_of = None;
+ let mut url = None;
+ let mut name = None;
+ for child in mirror_element.children {
+ match child.name.as_str() {
+ "id" => id = child.text,
+ "mirror_of" => mirror_of = child.text,
+ "url" => url = child.text,
+ "name" => name = child.text,
+ _ => {}
+ }
+ }
+
+ Mirror {
+ id,
+ mirror_of,
+ url,
+ name,
+ }
+}
+
+fn get_profile(profile_element: Node) -> Profile {
+ let mut id = None;
+ let mut activation = None;
+ let mut properties = vec![];
+ let mut repositories = vec![];
+ let mut plugin_repositories = vec![];
+
+ for child in profile_element.children {
+ match child.name.as_str() {
+ "id" => id = child.text,
+ "activation" => activation = Some(get_activation(child)),
+ "properties" => properties.append(&mut get_properties(child)),
+ "repositories" => repositories = get_repositories(child),
+ "pluginRepositories" => plugin_repositories = get_repositories(child),
+ _ => {}
+ }
+ }
+
+ Profile {
+ id,
+ activation,
+ properties,
+ repositories,
+ plugin_repositories,
+ }
+}
+
+fn get_activation(activation_element: Node) -> Activation {
+ let mut active_by_default = false;
+ let mut jdk = None;
+ let mut os = None;
+ let mut property = None;
+ let mut file = None;
+ for child in activation_element.children {
+ match child.name.as_str() {
+ "activeByDefault" => {
+ active_by_default = child.text.map(|b| b == "true").unwrap_or(false)
+ }
+ "jdk" => jdk = child.text,
+ "os" => os = Some(get_activation_os(child)),
+ "property" => property = Some(get_activation_property(child)),
+ "file" => file = Some(get_activation_file(child)),
+ _ => {}
+ }
+ }
+
+ Activation {
+ active_by_default,
+ jdk,
+ os,
+ property,
+ file,
+ }
+}
+
+fn get_properties(element: Node) -> Vec {
+ let mut properties = vec![];
+ for child in element.children {
+ properties.push(Property {
+ name: child.name,
+ value: child.text,
+ });
+ }
+ properties
+}
+
+fn get_repositories(element: Node) -> Vec {
+ let mut repositories = vec![];
+
+ for child in element.children {
+ match child.name.as_str() {
+ "repository" => repositories.push(get_repository(child)),
+ _ => {}
+ }
+ }
+ repositories
+}
+
+fn get_repository(element: Node) -> Repository {
+ let mut releases = None;
+ let mut snapshots = None;
+ let mut id = None;
+ let mut name = None;
+ let mut url = None;
+ let mut layout = "default".to_owned();
+
+ for child in element.children {
+ match child.name.as_str() {
+ "releases" => releases = Some(get_update_policy(child)),
+ "snapshots" => snapshots = Some(get_update_policy(child)),
+ "id" => id = child.text,
+ "name" => name = child.text,
+ "url" => url = child.text,
+ "layout" => layout = child.text.unwrap_or("default".to_owned()),
+ _ => {}
+ }
+ }
+ Repository {
+ releases,
+ snapshots,
+ id,
+ name,
+ url,
+ layout,
+ }
+}
+
+fn get_update_policy(element: Node) -> RepositoryPolicy {
+ let mut enabled = true;
+ let mut update_policy = None;
+ let mut checksum_policy = None;
+
+ for child in element.children {
+ match child.name.as_str() {
+ "enabled" => enabled = child.text.map(|b| b == "true").unwrap_or(true),
+ "update_policy" => update_policy = child.text,
+ "checksum_policy" => checksum_policy = child.text,
+ _ => {}
+ }
+ }
+ RepositoryPolicy {
+ enabled,
+ update_policy,
+ checksum_policy,
+ }
+}
+
+fn get_activation_os(element: Node) -> ActivationOs {
+ let mut name = None;
+ let mut family = None;
+ let mut arch = None;
+ let mut version = None;
+ for child in element.children {
+ match child.name.as_str() {
+ "name" => name = child.text,
+ "family" => family = child.text,
+ "arch" => arch = child.text,
+ "version" => version = child.text,
+ _ => {}
+ }
+ }
+
+ ActivationOs {
+ name,
+ family,
+ arch,
+ version,
+ }
+}
+
+fn get_activation_property(element: Node) -> ActivationProperty {
+ let mut name = None;
+ let mut value = None;
+ for child in element.children {
+ match child.name.as_str() {
+ "name" => name = child.text,
+ "value" => value = child.text,
+ _ => {}
+ }
+ }
+
+ ActivationProperty { name, value }
+}
+
+fn get_activation_file(element: Node) -> ActivationFile {
+ let mut missing = None;
+ let mut exists = None;
+ for child in element.children {
+ match child.name.as_str() {
+ "missing" => missing = child.text,
+ "exists" => exists = child.text,
+ _ => {}
+ }
+ }
+
+ ActivationFile { missing, exists }
+}
+
+fn get_settings_path() -> Result {
+ let mut settings = PathBuf::from_str(HOME.as_str()).map_err(|e| e.to_string())?;
+ settings.push(".m2/settings.xml");
+ if !settings.exists() {
+ settings = PathBuf::from_str(MAVEN_HOME.as_str()).map_err(|e| e.to_string())?;
+ settings.push("conf/settings.xml");
+ }
+ if !settings.exists() {
+ settings =
+ PathBuf::from_str(CUSTOM_SETTINGS_LOCATION.as_str()).map_err(|e| e.to_string())?;
+ if settings.is_dir() {
+ settings.push("settings.xml");
+ }
+ }
+ Ok(settings)
+}
+
+#[derive(Debug)]
+pub struct Settings {
+ local_repository: Option,
+ interactive_mode: bool,
+ use_plugin_registry: bool,
+ offline: bool,
+ proxies: Vec,
+ servers: Vec,
+ mirrors: Vec,
+ profiles: Vec,
+ active_profiles: Vec,
+ plugin_groups: Vec,
+}
+
+#[derive(Debug)]
+struct Server {
+ id: Option,
+ username: Option,
+ password: Option,
+ private_key: Option,
+ passphrase: Option,
+ file_permissions: Option,
+ directory_permissions: Option,
+ configuration: Option, //xsd:any
+}
+
+#[derive(Debug)]
+struct Mirror {
+ id: Option,
+ mirror_of: Option,
+ name: Option,
+ url: Option,
+}
+
+#[derive(Debug)]
+struct Proxy {
+ active: bool,
+ protocol: String,
+ username: Option,
+ password: Option,
+ port: usize,
+ host: Option,
+ non_proxy_hosts: Option,
+ id: Option,
+}
+
+#[derive(Debug)]
+struct Profile {
+ id: Option,
+ activation: Option,
+ properties: Vec,
+ repositories: Vec,
+ plugin_repositories: Vec,
+}
+
+#[derive(Debug)]
+struct Activation {
+ active_by_default: bool,
+ jdk: Option,
+ os: Option,
+ property: Option,
+ file: Option,
+}
+
+#[derive(Debug)]
+struct ActivationOs {
+ name: Option,
+ family: Option,
+ arch: Option,
+ version: Option,
+}
+
+#[derive(Debug)]
+struct ActivationProperty {
+ name: Option,
+ value: Option,
+}
+
+#[derive(Debug)]
+struct ActivationFile {
+ missing: Option,
+ exists: Option,
+}
+
+#[derive(Debug)]
+struct Property {
+ name: String,
+ value: Option,
+}
+
+#[derive(Debug)]
+struct Repository {
+ releases: Option,
+ snapshots: Option,
+ id: Option,
+ name: Option,
+ url: Option,
+ layout: String,
+}
+
+#[derive(Debug)]
+struct RepositoryPolicy {
+ enabled: bool,
+ update_policy: Option,
+ checksum_policy: Option,
+}
+
+#[cfg(test)]
+mod test {
+
+ use super::*;
+
+ #[test]
+ fn test() {
+ let settings = get_settings().expect("no fail");
+ println!("{:?}", settings);
+ }
+}
diff --git a/src/report.rs b/src/report.rs
index 9b951c6..da04055 100644
--- a/src/report.rs
+++ b/src/report.rs
@@ -1,9 +1,11 @@
use crate::maven::project::Project;
-use maud::{PreEscaped, html};
+use maud::{DOCTYPE, PreEscaped, html};
impl Project {
pub fn generate_dependency_html(&self) -> String {
let html = html! {
+ (DOCTYPE)
+ html {
(PreEscaped(r#"
@@ -27,26 +29,29 @@ impl Project {
}
-"#))
- h1{"Project Dependencies"}
- table{
- thead{
- tr {
- th{"Group ID"}
- th{"Artifact ID"}
- th{"Version"}
- }
- }
- tbody{
- @for dependency in &self.get_dependencies(&self.root) {
- tr {
- td { (dependency.group_id) }
- td { (dependency.artifact_id) }
- td { (dependency.version.clone().unwrap()) }
+ "#))
+ body{
+ h1{"Project Dependencies"}
+ table{
+ thead{
+ tr {
+ th{"Group ID"}
+ th{"Artifact ID"}
+ th{"Version"}
+ }
}
+ tbody{
+ @for dependency in &self.get_dependencies(&self.root) {
+ tr {
+ td { (dependency.group_id) }
+ td { (dependency.artifact_id) }
+ td { (dependency.version.clone().unwrap()) }
+ }
+ }
+ }
+ }
}
}
- }
};
html.into_string()
}
diff --git a/src/xml/dom_parser.rs b/src/xml/dom_parser.rs
index 644d9a5..d3f726b 100644
--- a/src/xml/dom_parser.rs
+++ b/src/xml/dom_parser.rs
@@ -2,9 +2,9 @@ use crate::xml::sax_parser::parse_string;
use crate::xml::{Attribute, SaxError, SaxHandler};
/// get a generic XML object (Document) from the xml contents. This is called DOM parsing
-pub fn get_document(xml: &str) -> Result {
+pub fn get_document(xml: impl Into) -> Result {
let mut dom_hax_handler = DomSaxHandler::new();
- parse_string(xml, Box::new(&mut dom_hax_handler))?;
+ parse_string(&xml.into(), Box::new(&mut dom_hax_handler))?;
Ok(dom_hax_handler.into_doc())
}
diff --git a/src/xml/sax_parser.rs b/src/xml/sax_parser.rs
index 6295e8e..ab4bcf4 100644
--- a/src/xml/sax_parser.rs
+++ b/src/xml/sax_parser.rs
@@ -22,6 +22,7 @@ struct SAXParser<'a> {
xml: Vec,
handler: Box<&'a mut dyn SaxHandler>,
position: usize,
+ current_line: usize,
current: char,
char_buffer: Vec,
namespace_stack: Vec<(String, isize)>,
@@ -35,6 +36,7 @@ impl<'a> SAXParser<'a> {
xml: xml.chars().collect(),
handler,
position: 0,
+ current_line: 0,
current: '\0',
char_buffer: Vec::new(),
namespace_stack: Vec::new(),
@@ -111,6 +113,9 @@ impl<'a> SAXParser<'a> {
while c.is_whitespace() {
self.skip_whitespace()?;
+ if self.current == '/' {
+ break;
+ }
atts.push(self.parse_attribute()?);
c = self.advance()?;
}
@@ -158,15 +163,21 @@ impl<'a> SAXParser<'a> {
let att_name = self.read_until("=")?;
self.skip_whitespace()?;
self.expect("=", "Expected =")?;
- self.expect("\"", "Expected start of attribute value")?;
+ self.skip_whitespace()?;
+ self.expect(
+ r#"""#,
+ &format!(
+ "Expected start of attribute value at line {}. Instead found [{}]",
+ self.current_line, self.current
+ ),
+ )?;
let att_value = self.read_until("\"")?;
if att_name.starts_with("xmlns:") {
let prefix = att_name[6..].to_string();
self.prefix_mapping
.insert(prefix.clone(), att_value.to_string());
- self.handler
- .start_prefix_mapping(&prefix, &att_value);
+ self.handler.start_prefix_mapping(&prefix, &att_value);
}
let namespace = if att_name == "xmlns" {
@@ -245,6 +256,10 @@ impl<'a> SAXParser<'a> {
} else {
'\0'
};
+ // print!("{}", self.current);
+ if self.current == '\n' {
+ self.current_line += 1;
+ }
Ok(self.current)
}