Skip to content

Commit 0dcce40

Browse files
anwaralameddindginev
authored andcommitted
Add no_ns variants for Node and RoNode methods
Add has_property_no_ns, remove_property_no_ns and get_property_node_no_ns Add get_property_node_ns
1 parent 6dd1af3 commit 0dcce40

4 files changed

Lines changed: 148 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
### Added
66

7-
* Node methods: `get_property_no_ns` (alias: `get_attribute_no_ns`), `get_properties_ns` (alias: `get_attributes_ns`)
7+
* Node methods: `get_property_no_ns` (alias: `get_attribute_no_ns`), `get_properties_ns` (alias: `get_attributes_ns`), `has_property_no_ns` (alias: `has_attribute_no_ns`), `remove_property_no_ns` (alias: `remove_attribute_no_ns`), `get_property_node_ns` (alias: `get_attribute_node_ns`), `get_property_node_no_ns` (alias: `get_attribute_node_no_ns`)
88
* Added implementations of `Hash`, `PartialEq` and `Eq` traits for `Namespace`
99

1010
## [0.3.3] 2023-17-07

src/readonly/tree.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,22 @@ impl RoNode {
275275
}
276276
}
277277

278+
/// Return an attribute in a namespace `ns` as a `Node` of type AttributeNode
279+
pub fn get_property_node_ns(self, name: &str, ns: &str) -> Option<RoNode> {
280+
let c_name = CString::new(name).unwrap();
281+
let c_ns = CString::new(ns).unwrap();
282+
let attr_node =
283+
unsafe { xmlHasNsProp(self.0, c_name.as_bytes().as_ptr(), c_ns.as_bytes().as_ptr()) };
284+
self.ptr_as_option(attr_node as xmlNodePtr)
285+
}
286+
287+
/// Return an attribute with no namespace as a `Node` of type AttributeNode
288+
pub fn get_property_node_no_ns(self, name: &str) -> Option<RoNode> {
289+
let c_name = CString::new(name).unwrap();
290+
let attr_node = unsafe { xmlHasNsProp(self.0, c_name.as_bytes().as_ptr(), ptr::null()) };
291+
self.ptr_as_option(attr_node as xmlNodePtr)
292+
}
293+
278294
/// Alias for get_property
279295
pub fn get_attribute(self, name: &str) -> Option<String> {
280296
self.get_property(name)
@@ -295,6 +311,16 @@ impl RoNode {
295311
self.get_property_node(name)
296312
}
297313

314+
/// Alias for get_property_node_ns
315+
pub fn get_attribute_node_ns(self, name: &str, ns: &str) -> Option<RoNode> {
316+
self.get_property_node_ns(name, ns)
317+
}
318+
319+
/// Alias for get_property_node_no_ns
320+
pub fn get_attribute_node_no_ns(self, name: &str) -> Option<RoNode> {
321+
self.get_property_node_no_ns(name)
322+
}
323+
298324
/// Get a copy of the attributes of this node
299325
pub fn get_properties(self) -> HashMap<String, String> {
300326
let mut attributes = HashMap::new();
@@ -354,6 +380,7 @@ impl RoNode {
354380
let value_ptr = unsafe { xmlHasProp(self.0, c_name.as_bytes().as_ptr()) };
355381
!value_ptr.is_null()
356382
}
383+
357384
/// Check if property `name` in namespace `ns` exists
358385
pub fn has_property_ns(self, name: &str, ns: &str) -> bool {
359386
let c_name = CString::new(name).unwrap();
@@ -362,15 +389,29 @@ impl RoNode {
362389
unsafe { xmlHasNsProp(self.0, c_name.as_bytes().as_ptr(), c_ns.as_bytes().as_ptr()) };
363390
!value_ptr.is_null()
364391
}
392+
393+
/// Check if property `name` with no namespace exists
394+
pub fn has_property_no_ns(self, name: &str) -> bool {
395+
let c_name = CString::new(name).unwrap();
396+
let value_ptr = unsafe { xmlHasNsProp(self.0, c_name.as_bytes().as_ptr(), ptr::null()) };
397+
!value_ptr.is_null()
398+
}
399+
365400
/// Alias for has_property
366401
pub fn has_attribute(self, name: &str) -> bool {
367402
self.has_property(name)
368403
}
404+
369405
/// Alias for has_property_ns
370406
pub fn has_attribute_ns(self, name: &str, ns: &str) -> bool {
371407
self.has_property_ns(name, ns)
372408
}
373409

410+
/// Alias for has_property_no_ns
411+
pub fn has_attribute_no_ns(self, name: &str) -> bool {
412+
self.has_property_no_ns(name)
413+
}
414+
374415
/// Gets the active namespace associated of this node
375416
pub fn get_namespace(self) -> Option<Namespace> {
376417
let ns_ptr = xmlNodeNs(self.0);

src/tree/node.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,12 +481,35 @@ impl Node {
481481
}
482482
}
483483

484+
/// Return an attribute in a namespace `ns` as a `Node` of type AttributeNode
485+
pub fn get_property_node_ns(&self, name: &str, ns: &str) -> Option<Node> {
486+
let c_name = CString::new(name).unwrap();
487+
let c_ns = CString::new(ns).unwrap();
488+
let attr_node = unsafe {
489+
xmlHasNsProp(
490+
self.node_ptr(),
491+
c_name.as_bytes().as_ptr(),
492+
c_ns.as_bytes().as_ptr(),
493+
)
494+
};
495+
self.ptr_as_option(attr_node as xmlNodePtr)
496+
}
497+
498+
/// Return an attribute with no namespace as a `Node` of type AttributeNode
499+
pub fn get_property_node_no_ns(&self, name: &str) -> Option<Node> {
500+
let c_name = CString::new(name).unwrap();
501+
let attr_node =
502+
unsafe { xmlHasNsProp(self.node_ptr(), c_name.as_bytes().as_ptr(), ptr::null()) };
503+
self.ptr_as_option(attr_node as xmlNodePtr)
504+
}
505+
484506
/// Check if a property has been defined, without allocating its value
485507
pub fn has_property(&self, name: &str) -> bool {
486508
let c_name = CString::new(name).unwrap();
487509
let value_ptr = unsafe { xmlHasProp(self.node_ptr(), c_name.as_bytes().as_ptr()) };
488510
!value_ptr.is_null()
489511
}
512+
490513
/// Check if property `name` in namespace `ns` exists
491514
pub fn has_property_ns(&self, name: &str, ns: &str) -> bool {
492515
let c_name = CString::new(name).unwrap();
@@ -500,6 +523,15 @@ impl Node {
500523
};
501524
!value_ptr.is_null()
502525
}
526+
527+
/// Check if property `name` with no namespace exists
528+
pub fn has_property_no_ns(&self, name: &str) -> bool {
529+
let c_name = CString::new(name).unwrap();
530+
let value_ptr =
531+
unsafe { xmlHasNsProp(self.node_ptr(), c_name.as_bytes().as_ptr(), ptr::null()) };
532+
!value_ptr.is_null()
533+
}
534+
503535
/// Alias for has_property
504536
pub fn has_attribute(&self, name: &str) -> bool {
505537
self.has_property(name)
@@ -509,6 +541,11 @@ impl Node {
509541
self.has_property_ns(name, ns)
510542
}
511543

544+
/// Alias for has_property_no_ns
545+
pub fn has_attribute_no_ns(&self, name: &str) -> bool {
546+
self.has_property_no_ns(name)
547+
}
548+
512549
/// Sets the value of property `name` to `value`
513550
pub fn set_property(
514551
&mut self,
@@ -601,6 +638,33 @@ impl Node {
601638
}
602639
}
603640

641+
/// Removes the property of given `name` with no namespace
642+
pub fn remove_property_no_ns(&mut self, name: &str) -> Result<(), Box<dyn Error + Send + Sync>> {
643+
let c_name = CString::new(name).unwrap();
644+
let attr_node = unsafe {
645+
xmlHasNsProp(
646+
self.node_ptr_mut()?,
647+
c_name.as_bytes().as_ptr(),
648+
ptr::null(),
649+
)
650+
};
651+
if !attr_node.is_null() {
652+
let remove_prop_status = unsafe { xmlRemoveProp(attr_node) };
653+
if remove_prop_status == 0 {
654+
Ok(())
655+
} else {
656+
// Propagate libxml2 failure to remove
657+
Err(From::from(format!(
658+
"libxml2 failed to remove property with status: {:?}",
659+
remove_prop_status
660+
)))
661+
}
662+
} else {
663+
// silently no-op if asked to remove a property which is not present
664+
Ok(())
665+
}
666+
}
667+
604668
/// Alias for get_property
605669
pub fn get_attribute(&self, name: &str) -> Option<String> {
606670
self.get_property(name)
@@ -621,6 +685,16 @@ impl Node {
621685
self.get_property_node(name)
622686
}
623687

688+
/// Alias for get_property_node_ns
689+
pub fn get_attribute_node_ns(&self, name: &str, ns: &str) -> Option<Node> {
690+
self.get_property_node_ns(name, ns)
691+
}
692+
693+
/// Alias for get_property_node_no_ns
694+
pub fn get_attribute_node_no_ns(&self, name: &str) -> Option<Node> {
695+
self.get_property_node_no_ns(name)
696+
}
697+
624698
/// Alias for set_property
625699
pub fn set_attribute(
626700
&mut self,
@@ -653,6 +727,11 @@ impl Node {
653727
self.remove_property_ns(name, ns)
654728
}
655729

730+
/// Alias for remove_property_no_ns
731+
pub fn remove_attribute_no_ns(&mut self, name: &str) -> Result<(), Box<dyn Error + Send + Sync>> {
732+
self.remove_property_no_ns(name)
733+
}
734+
656735
/// Get a copy of the attributes of this node
657736
pub fn get_properties(&self) -> HashMap<String, String> {
658737
let mut attributes = HashMap::new();

tests/tree_tests.rs

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,12 @@ fn node_attributes_ns_accessor() {
144144
);
145145

146146
// Has
147-
// TODO include this when `has_attribute_no_ns` is implemented
148-
// assert!(child.has_attribute("attribute"));
147+
assert!(child.has_attribute("attribute"));
148+
assert!(child.has_attribute_no_ns("attribute"));
149+
assert!(child.has_attribute_ns("attribute", "http://www.example.com/myns"),);
150+
assert!(child.has_attribute("attr"));
151+
assert!(!child.has_attribute_no_ns("attr"));
152+
assert!(child.has_attribute_ns("attr", "http://www.example.com/myns"));
149153

150154
// Get
151155
assert_eq!(
@@ -162,13 +166,18 @@ fn node_attributes_ns_accessor() {
162166
);
163167

164168
// Get as node
165-
// TODO include this when `get_attribute_node_ns` and
166-
// `get_attribute_node_no_ns` are implemented
167-
// let attr_node_opt = child.get_attribute_node("attribute");
168-
// assert!(attr_node_opt.is_some());
169-
// let attr_node = attr_node_opt.unwrap();
170-
// assert_eq!(attr_node.get_name(), "attribute");
171-
// assert_eq!(attr_node.get_type(), Some(NodeType::AttributeNode));
169+
let attr_node_opt = child.get_attribute_node_no_ns("attribute");
170+
assert!(attr_node_opt.is_some());
171+
let attr_node = attr_node_opt.unwrap();
172+
assert_eq!(attr_node.get_name(), "attribute");
173+
assert_eq!(attr_node.get_type(), Some(NodeType::AttributeNode));
174+
let attr_node_opt = child.get_attribute_node_no_ns("attr");
175+
assert!(attr_node_opt.is_none());
176+
let attr_node_opt = child.get_attribute_node_ns("attr", "http://www.example.com/myns");
177+
assert!(attr_node_opt.is_some());
178+
let attr_node = attr_node_opt.unwrap();
179+
assert_eq!(attr_node.get_name(), "attr");
180+
assert_eq!(attr_node.get_type(), Some(NodeType::AttributeNode));
172181

173182
// Set
174183
assert!(child.set_attribute("attribute", "setter_value").is_ok());
@@ -184,13 +193,13 @@ fn node_attributes_ns_accessor() {
184193
Some("setter_value".to_string())
185194
);
186195
// Remove
187-
// TODO include this when `remove_attribute_no_ns` is implemented
188-
// assert!(child.remove_attribute("attribute").is_ok());
189-
// assert_eq!(child.get_attribute("attribute"), None);
190-
// assert_eq!(child.has_attribute("attribute"), false);
196+
assert!(child.has_attribute_no_ns("attribute"));
197+
assert!(child.remove_attribute_no_ns("attribute").is_ok());
198+
assert_eq!(child.get_attribute_no_ns("attribute"), None);
199+
assert!(!child.has_attribute_no_ns("attribute"));
191200
// Recount
192-
// let attributes = child.get_attributes_ns();
193-
// assert_eq!(attributes.len(), 2);
201+
let attributes = child.get_attributes_ns();
202+
assert_eq!(attributes.len(), 2);
194203
}
195204

196205
#[test]
@@ -321,13 +330,9 @@ fn attribute_no_namespace() {
321330
assert!(foo_no_ns_attr.is_some());
322331
assert_eq!(foo_no_ns_attr.unwrap(), "no_ns");
323332

324-
// TODO: include this when `remove_attribute_no_ns` is implemented
325-
// It's not possible use remove_attribute here as it removes the first
326-
// attribute found with the local name regardless of the namespace; here it
327-
// removes the attribute with the namespace
328-
// assert!(element.remove_attribute_no_ns("foo").is_ok());
329-
// let foo_no_ns_attr = element.get_attribute_no_ns("foo");
330-
// assert!(foo_no_ns_attr.is_none());
333+
assert!(element.remove_attribute_no_ns("foo").is_ok());
334+
let foo_no_ns_attr = element.get_attribute_no_ns("foo");
335+
assert!(foo_no_ns_attr.is_none());
331336

332337
assert!(element.set_attribute("bar", "bar").is_ok());
333338
let bar_no_ns_attr = element.get_attribute_no_ns("bar");

0 commit comments

Comments
 (0)