diff --git a/CHANGELOG.md b/CHANGELOG.md index fe8d478495..93583d51e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,10 +3,11 @@ ## [0.3.1] (in development) * Added: Thanks to @lepapareil, @hurlenko and @ballsteve for contributing installation docs for Windows and MacOS. +* Added: `Node` and `RoNode` now have `has_property` (alias `has_attribute`) and `has_property_ns` (alias `has_attribute_ns`) to check attribute presence without allocating the value. ## [0.3.0] 2021-27-05 -* Change `Parser::parse_file/string_with_encoding` to `Parser::parse_file/string_with_options`. +* Change `Parser::parse_file/string_with_encoding` to `Parser::parse_file/string_with_options`. * Introduce `ParserOptions` which encapsulates the forced encoding setting together with libxml2s HTML and XML parser options. diff --git a/src/readonly/tree.rs b/src/readonly/tree.rs index 0a63ae8ee0..d7d62fb242 100644 --- a/src/readonly/tree.rs +++ b/src/readonly/tree.rs @@ -303,6 +303,29 @@ impl RoNode { self.get_properties() } + /// Check if a property has been defined, without allocating its value + pub fn has_property(self, name: &str) -> bool { + let c_name = CString::new(name).unwrap(); + let value_ptr = unsafe { xmlHasProp(self.0, c_name.as_bytes().as_ptr()) }; + !value_ptr.is_null() + } + /// Check if property `name` in namespace `ns` exists + pub fn has_property_ns(self, name: &str, ns: &str) -> bool { + let c_name = CString::new(name).unwrap(); + let c_ns = CString::new(ns).unwrap(); + let value_ptr = + unsafe { xmlHasNsProp(self.0, c_name.as_bytes().as_ptr(), c_ns.as_bytes().as_ptr()) }; + !value_ptr.is_null() + } + /// Alias for has_property + pub fn has_attribute(self, name: &str) -> bool { + self.has_property(name) + } + /// Alias for has_property_ns + pub fn has_attribute_ns(self, name: &str, ns: &str) -> bool { + self.has_property_ns(name, ns) + } + /// Gets the active namespace associated of this node pub fn get_namespace(self) -> Option { let ns_ptr = xmlNodeNs(self.0); diff --git a/src/tree/node.rs b/src/tree/node.rs index a127d54ea3..55c7b8d8ae 100644 --- a/src/tree/node.rs +++ b/src/tree/node.rs @@ -460,6 +460,29 @@ impl Node { } } + /// Check if a property has been defined, without allocating its value + pub fn has_property(&self, name: &str) -> bool { + let c_name = CString::new(name).unwrap(); + let value_ptr = unsafe { xmlHasProp(self.node_ptr(), c_name.as_bytes().as_ptr()) }; + !value_ptr.is_null() + } + /// Check if property `name` in namespace `ns` exists + pub fn has_property_ns(&self, name: &str, ns: &str) -> bool { + let c_name = CString::new(name).unwrap(); + let c_ns = CString::new(ns).unwrap(); + let value_ptr = + unsafe { xmlHasNsProp(self.node_ptr(), c_name.as_bytes().as_ptr(), c_ns.as_bytes().as_ptr()) }; + !value_ptr.is_null() + } + /// Alias for has_property + pub fn has_attribute(&self, name: &str) -> bool { + self.has_property(name) + } + /// Alias for has_property_ns + pub fn has_attribute_ns(&self, name: &str, ns: &str) -> bool { + self.has_property_ns(name, ns) + } + /// Sets the value of property `name` to `value` pub fn set_property(&mut self, name: &str, value: &str) -> Result<(), Box> { let c_name = CString::new(name).unwrap(); diff --git a/tests/tree_tests.rs b/tests/tree_tests.rs index cd17ebaf59..7d8bbe1698 100644 --- a/tests/tree_tests.rs +++ b/tests/tree_tests.rs @@ -83,6 +83,8 @@ fn node_attributes_accessor() { assert_eq!(attributes.len(), 1); assert_eq!(attributes.get("attribute"), Some(&"value".to_string())); + // Has + assert_eq!(child.has_attribute("attribute"), true); // Get assert_eq!(child.get_attribute("attribute"), Some("value".to_string())); // Get as node @@ -101,6 +103,7 @@ fn node_attributes_accessor() { // Remove assert!(child.remove_attribute("attribute").is_ok()); assert_eq!(child.get_attribute("attribute"), None); + assert_eq!(child.has_attribute("attribute"), false); // Recount let attributes = child.get_attributes(); assert_eq!(attributes.len(), 0); @@ -239,10 +242,14 @@ fn can_manage_attributes() { let value = "examplevalue"; let pre_value = hello_element.get_attribute(key); assert_eq!(pre_value, None); + let pre_prop_check = hello_element.has_property(key); + assert_eq!(pre_prop_check, false); let pre_prop_value = hello_element.get_property(key); assert_eq!(pre_prop_value, None); assert!(hello_element.set_attribute(key, value).is_ok()); + let new_check = hello_element.has_attribute(key); + assert_eq!(new_check, true); let new_value = hello_element.get_attribute(key); assert_eq!(new_value, Some(value.to_owned())); }