11import abc
22from enum import Enum
3- from typing import Any , Callable , Dict , Generic , List , Optional , Sequence , Tuple , TypeVar
3+ from typing import Any , Callable , Dict , Generic , Iterable , List , Optional , Sequence , Tuple , TypeVar
44
55from pydantic_xml .typedefs import NsMap
66
@@ -21,6 +21,13 @@ def tag(self) -> str:
2121 Xml element tag.
2222 """
2323
24+ @property
25+ @abc .abstractmethod
26+ def nsmap (self ) -> Optional [NsMap ]:
27+ """
28+ Xml element namespace map.
29+ """
30+
2431 @abc .abstractmethod
2532 def is_empty (self ) -> bool :
2633 """
@@ -64,6 +71,15 @@ def pop_text(self) -> Optional[str]:
6471 :return: element text
6572 """
6673
74+ @abc .abstractmethod
75+ def pop_tail (self ) -> Optional [str ]:
76+ """
77+ Extracts the tail from the xml element.
78+ All subsequent calls return `None`.
79+
80+ :return: element tail
81+ """
82+
6783 @abc .abstractmethod
6884 def pop_attrib (self , name : str ) -> Optional [str ]:
6985 """
@@ -83,12 +99,22 @@ def pop_attributes(self) -> Optional[Dict[str, str]]:
8399 """
84100
85101 @abc .abstractmethod
86- def pop_element (self , tag : str , search_mode : 'SearchMode' ) -> Optional ['XmlElementReader' ]:
102+ def pop_elements (self ) -> Tuple ['XmlElementReader' , ...]:
103+ """
104+ Extracts all sub-elements from the xml element.
105+ All subsequent calls return empty list.
106+
107+ :return: element sub-elements
108+ """
109+
110+ @abc .abstractmethod
111+ def pop_element (self , tag : str , search_mode : 'SearchMode' , remove : bool = False ) -> Optional ['XmlElementReader' ]:
87112 """
88113 Extracts a sub-element from the xml element matching `tag`.
89114
90115 :param tag: element tag
91116 :param search_mode: element search mode
117+ :param remove: remove all entities from the element
92118 :return: sub-element
93119 """
94120
@@ -280,7 +306,7 @@ def __init__(
280306 text : Optional [str ] = None ,
281307 tail : Optional [str ] = None ,
282308 attributes : Optional [Dict [str , str ]] = None ,
283- elements : Optional [List ['XmlElement[NativeElement]' ]] = None ,
309+ elements : Optional [Iterable ['XmlElement[NativeElement]' ]] = None ,
284310 nsmap : Optional [NsMap ] = None ,
285311 sourceline : int = - 1 ,
286312 ):
@@ -290,7 +316,7 @@ def __init__(
290316 text = text ,
291317 tail = tail ,
292318 attrib = dict (attributes ) if attributes is not None else None ,
293- elements = elements or [],
319+ elements = list ( elements ) if elements is not None else [],
294320 next_element_idx = 0 ,
295321 )
296322 self ._sourceline = sourceline
@@ -303,6 +329,10 @@ def get_sourceline(self) -> int:
303329 def tag (self ) -> str :
304330 return self ._tag
305331
332+ @property
333+ def nsmap (self ) -> Optional [NsMap ]:
334+ return self ._nsmap
335+
306336 def create_snapshot (self ) -> 'XmlElement[NativeElement]' :
307337 element = self .__class__ (
308338 tag = self ._tag ,
@@ -359,6 +389,11 @@ def pop_text(self) -> Optional[str]:
359389
360390 return result
361391
392+ def pop_tail (self ) -> Optional [str ]:
393+ result , self ._state .tail = self ._state .tail , None
394+
395+ return result
396+
362397 def pop_attrib (self , name : str ) -> Optional [str ]:
363398 return self ._state .attrib .pop (name , None ) if self ._state .attrib else None
364399
@@ -367,10 +402,33 @@ def pop_attributes(self) -> Optional[Dict[str, str]]:
367402
368403 return result
369404
370- def pop_element (self , tag : str , search_mode : 'SearchMode' ) -> Optional ['XmlElement[NativeElement]' ]:
405+ def pop_elements (self ) -> Tuple ['XmlElement[NativeElement]' , ...]:
406+ elements , self ._state .elements = self ._state .elements , []
407+ self ._state .next_element_idx = 0
408+
409+ return tuple (elements )
410+
411+ def pop_element (
412+ self ,
413+ tag : str ,
414+ search_mode : 'SearchMode' ,
415+ remove : bool = False ,
416+ ) -> Optional ['XmlElement[NativeElement]' ]:
371417 searcher : Searcher [NativeElement ] = get_searcher (search_mode )
372418
373- return searcher (self ._state , tag , False , True )
419+ element = searcher (self ._state , tag , False , True )
420+ if element is not None and remove :
421+ return self .__class__ (
422+ tag = element .tag ,
423+ nsmap = element .nsmap ,
424+ text = element .pop_text (),
425+ tail = element .pop_tail (),
426+ attributes = element .pop_attributes (),
427+ elements = element .pop_elements (),
428+ sourceline = element .get_sourceline (),
429+ )
430+
431+ return element
374432
375433 def find_sub_element (self , path : Sequence [str ], search_mode : 'SearchMode' ) -> PathT ['XmlElement[NativeElement]' ]:
376434 assert len (path ) > 0 , "path can't be empty"
0 commit comments