phml.utils.locate.find
Collection of utility methods to find one or many of a specific node.
1"""phml.utils.locate.find 2 3Collection of utility methods to find one or many of a specific node. 4""" 5 6from typing import Optional 7 8from phml.nodes import AST, All_Nodes, Element, Root 9from phml.utils.travel import path, walk 10from phml.utils.validate import Test, check 11 12__all__ = [ 13 "ancestor", 14 "find", 15 "find_all", 16 "find_after", 17 "find_all_after", 18 "find_all_before", 19 "find_before", 20 "find_all_between", 21] 22 23 24def ancestor(*nodes: All_Nodes) -> Optional[All_Nodes]: 25 """Get the common ancestor between two nodes. 26 27 Args: 28 *nodes (All_Nodes): A list of any number of nodes 29 to find the common ancestor form. Worst case it will 30 return the root. 31 32 Returns: 33 Optional[All_Nodes]: The node that is the common 34 ancestor or None if not found. 35 """ 36 total_path: list = None 37 38 def filter_func(node, total_path) -> bool: 39 return node in total_path 40 41 for node in nodes: 42 if total_path is not None: 43 total_path = list(filter(lambda n: filter_func(n, total_path), path(node))) 44 else: 45 total_path = path(node) 46 47 return total_path[-1] if len(total_path) > 0 else None 48 49 50def find(start: Root | Element | AST, condition: Test, strict: bool = True) -> Optional[All_Nodes]: 51 """Walk the nodes children and return the desired node. 52 53 Returns the first node that matches the condition. 54 55 Args: 56 start (Root | Element): Starting node. 57 condition (Test): Condition to check against each node. 58 59 Returns: 60 Optional[All_Nodes]: Returns the found node or None if not found. 61 """ 62 if isinstance(start, AST): 63 start = start.tree 64 65 for node in walk(start): 66 if check(node, condition, strict=strict): 67 return node 68 69 return None 70 71 72def find_all(start: Root | Element | AST, condition: Test, strict: bool = True) -> list[All_Nodes]: 73 """Find all nodes that match the condition. 74 75 Args: 76 start (Root | Element): Starting node. 77 condition (Test): Condition to apply to each node. 78 79 Returns: 80 list[All_Nodes]: List of found nodes. Empty if no nodes are found. 81 """ 82 if isinstance(start, AST): 83 start = start.tree 84 85 results = [] 86 for node in walk(start): 87 if check(node, condition, strict=strict): 88 results.append(node) 89 return results 90 91 92def find_after( 93 start: Root | Element | AST, 94 condition: Optional[Test] = None, 95 strict: bool = True, 96) -> Optional[All_Nodes]: 97 """Get the first sibling node following the provided node that matches 98 the condition. 99 100 Args: 101 start (All_Nodes): Node to get sibling from. 102 condition (Test): Condition to check against each node. 103 104 Returns: 105 Optional[All_Nodes]: Returns the first sibling or None if there 106 are no siblings. 107 """ 108 if isinstance(start, AST): 109 start = start.tree 110 111 idx = start.parent.children.index(start) 112 if len(start.parent.children) - 1 > idx: 113 for node in start.parent.children[idx + 1 :]: 114 if condition is not None: 115 if check(node, condition, strict=strict): 116 return node 117 else: 118 return node 119 return None 120 121 122def find_all_after( 123 start: Element, 124 condition: Optional[Test] = None, 125 strict: bool = True, 126) -> list[All_Nodes]: 127 """Get all sibling nodes that match the condition. 128 129 Args: 130 start (All_Nodes): Node to get siblings from. 131 condition (Test): Condition to check against each node. 132 133 Returns: 134 list[All_Nodes]: Returns the all siblings that match the 135 condition or an empty list if none were found. 136 """ 137 idx = start.parent.children.index(start) 138 matches = [] 139 140 if len(start.parent.children) - 1 > idx: 141 for node in start.parent.children[idx + 1 :]: 142 if condition is not None: 143 if check(node, condition, strict=strict): 144 matches.append(node) 145 else: 146 matches.append(node) 147 148 return matches 149 150 151def find_before( 152 start: Element, 153 condition: Optional[Test] = None, 154 strict: bool = True, 155) -> Optional[All_Nodes]: 156 """Find the first sibling node before the given node. If a condition is applied 157 then it will be the first sibling node that passes that condition. 158 159 Args: 160 start (All_Nodes): The node to find the previous sibling from. 161 condition (Optional[Test]): The test that is applied to each node. 162 163 Returns: 164 Optional[All_Nodes]: The first node before the given node 165 or None if no prior siblings. 166 """ 167 if isinstance(start, AST): 168 start = start.tree 169 170 idx = start.parent.children.index(start) 171 if idx > 0: 172 for node in start.parent.children[idx - 1 :: -1]: 173 if condition is not None: 174 if check(node, condition, strict=strict): 175 return node 176 else: 177 return node 178 return None 179 180 181def find_all_before( 182 start: Element, 183 condition: Optional[Test] = None, 184 strict: bool = True, 185) -> list[All_Nodes]: 186 """Find all nodes that come before the given node. 187 188 Args: 189 start (All_Nodes): The node to find all previous siblings from. 190 condition (Optional[Test]): The condition to apply to each node. 191 192 Returns: 193 list[All_Nodes]: A list of nodes that come before the given node. 194 Empty list if no nodes were found. 195 """ 196 idx = start.parent.children.index(start) 197 matches = [] 198 199 if idx > 0: 200 for node in start.parent.children[:idx]: 201 if condition is not None: 202 if check(node, condition, strict=strict): 203 matches.append(node) 204 else: 205 matches.append(node) 206 return matches 207 208 209def find_all_between( 210 parent: Root | Element | AST, 211 start: Optional[int] = 0, 212 end: Optional[int] = 0, 213 condition: Optional[Test] = None, 214 _range: Optional[slice] = None, 215 strict: bool = True, 216) -> list[All_Nodes]: 217 """Find all sibling nodes in parent that meet the provided condition from start index 218 to end index. 219 220 Args: 221 parent (Root | Element): The parent element to get nodes from. 222 start (int, optional): The starting index, inclusive. Defaults to 0. 223 end (int, optional): The ending index, exclusive. Defaults to 0. 224 condition (Test, optional): Condition to apply to each node. Defaults to None. 225 _range (slice, optional): Slice to apply to the parent nodes children instead of start and 226 end indecies. Defaults to None. 227 228 Returns: 229 list[All_Nodes]: List of all matching nodes or an empty list if none were found. 230 """ 231 if isinstance(parent, AST): 232 parent = parent.tree 233 234 if _range is not None: 235 start = _range.start 236 end = _range.stop 237 238 results = [] 239 if start in range(0, end) and end in range(start, len(parent.children) + 1): 240 for node in parent.children[start:end]: 241 if condition is not None: 242 if check(node, condition, strict=strict): 243 results.append(node) 244 else: 245 results.append(node) 246 return results
25def ancestor(*nodes: All_Nodes) -> Optional[All_Nodes]: 26 """Get the common ancestor between two nodes. 27 28 Args: 29 *nodes (All_Nodes): A list of any number of nodes 30 to find the common ancestor form. Worst case it will 31 return the root. 32 33 Returns: 34 Optional[All_Nodes]: The node that is the common 35 ancestor or None if not found. 36 """ 37 total_path: list = None 38 39 def filter_func(node, total_path) -> bool: 40 return node in total_path 41 42 for node in nodes: 43 if total_path is not None: 44 total_path = list(filter(lambda n: filter_func(n, total_path), path(node))) 45 else: 46 total_path = path(node) 47 48 return total_path[-1] if len(total_path) > 0 else None
Get the common ancestor between two nodes.
Args
- *nodes (All_Nodes): A list of any number of nodes
- to find the common ancestor form. Worst case it will
- return the root.
Returns
Optional[All_Nodes]: The node that is the common ancestor or None if not found.
51def find(start: Root | Element | AST, condition: Test, strict: bool = True) -> Optional[All_Nodes]: 52 """Walk the nodes children and return the desired node. 53 54 Returns the first node that matches the condition. 55 56 Args: 57 start (Root | Element): Starting node. 58 condition (Test): Condition to check against each node. 59 60 Returns: 61 Optional[All_Nodes]: Returns the found node or None if not found. 62 """ 63 if isinstance(start, AST): 64 start = start.tree 65 66 for node in walk(start): 67 if check(node, condition, strict=strict): 68 return node 69 70 return None
Walk the nodes children and return the desired node.
Returns the first node that matches the condition.
Args
- start (Root | Element): Starting node.
- condition (Test): Condition to check against each node.
Returns
Optional[All_Nodes]: Returns the found node or None if not found.
73def find_all(start: Root | Element | AST, condition: Test, strict: bool = True) -> list[All_Nodes]: 74 """Find all nodes that match the condition. 75 76 Args: 77 start (Root | Element): Starting node. 78 condition (Test): Condition to apply to each node. 79 80 Returns: 81 list[All_Nodes]: List of found nodes. Empty if no nodes are found. 82 """ 83 if isinstance(start, AST): 84 start = start.tree 85 86 results = [] 87 for node in walk(start): 88 if check(node, condition, strict=strict): 89 results.append(node) 90 return results
Find all nodes that match the condition.
Args
- start (Root | Element): Starting node.
- condition (Test): Condition to apply to each node.
Returns
list[All_Nodes]: List of found nodes. Empty if no nodes are found.
93def find_after( 94 start: Root | Element | AST, 95 condition: Optional[Test] = None, 96 strict: bool = True, 97) -> Optional[All_Nodes]: 98 """Get the first sibling node following the provided node that matches 99 the condition. 100 101 Args: 102 start (All_Nodes): Node to get sibling from. 103 condition (Test): Condition to check against each node. 104 105 Returns: 106 Optional[All_Nodes]: Returns the first sibling or None if there 107 are no siblings. 108 """ 109 if isinstance(start, AST): 110 start = start.tree 111 112 idx = start.parent.children.index(start) 113 if len(start.parent.children) - 1 > idx: 114 for node in start.parent.children[idx + 1 :]: 115 if condition is not None: 116 if check(node, condition, strict=strict): 117 return node 118 else: 119 return node 120 return None
Get the first sibling node following the provided node that matches the condition.
Args
- start (All_Nodes): Node to get sibling from.
- condition (Test): Condition to check against each node.
Returns
Optional[All_Nodes]: Returns the first sibling or None if there are no siblings.
123def find_all_after( 124 start: Element, 125 condition: Optional[Test] = None, 126 strict: bool = True, 127) -> list[All_Nodes]: 128 """Get all sibling nodes that match the condition. 129 130 Args: 131 start (All_Nodes): Node to get siblings from. 132 condition (Test): Condition to check against each node. 133 134 Returns: 135 list[All_Nodes]: Returns the all siblings that match the 136 condition or an empty list if none were found. 137 """ 138 idx = start.parent.children.index(start) 139 matches = [] 140 141 if len(start.parent.children) - 1 > idx: 142 for node in start.parent.children[idx + 1 :]: 143 if condition is not None: 144 if check(node, condition, strict=strict): 145 matches.append(node) 146 else: 147 matches.append(node) 148 149 return matches
Get all sibling nodes that match the condition.
Args
- start (All_Nodes): Node to get siblings from.
- condition (Test): Condition to check against each node.
Returns
list[All_Nodes]: Returns the all siblings that match the condition or an empty list if none were found.
182def find_all_before( 183 start: Element, 184 condition: Optional[Test] = None, 185 strict: bool = True, 186) -> list[All_Nodes]: 187 """Find all nodes that come before the given node. 188 189 Args: 190 start (All_Nodes): The node to find all previous siblings from. 191 condition (Optional[Test]): The condition to apply to each node. 192 193 Returns: 194 list[All_Nodes]: A list of nodes that come before the given node. 195 Empty list if no nodes were found. 196 """ 197 idx = start.parent.children.index(start) 198 matches = [] 199 200 if idx > 0: 201 for node in start.parent.children[:idx]: 202 if condition is not None: 203 if check(node, condition, strict=strict): 204 matches.append(node) 205 else: 206 matches.append(node) 207 return matches
Find all nodes that come before the given node.
Args
- start (All_Nodes): The node to find all previous siblings from.
- condition (Optional[Test]): The condition to apply to each node.
Returns
list[All_Nodes]: A list of nodes that come before the given node. Empty list if no nodes were found.
152def find_before( 153 start: Element, 154 condition: Optional[Test] = None, 155 strict: bool = True, 156) -> Optional[All_Nodes]: 157 """Find the first sibling node before the given node. If a condition is applied 158 then it will be the first sibling node that passes that condition. 159 160 Args: 161 start (All_Nodes): The node to find the previous sibling from. 162 condition (Optional[Test]): The test that is applied to each node. 163 164 Returns: 165 Optional[All_Nodes]: The first node before the given node 166 or None if no prior siblings. 167 """ 168 if isinstance(start, AST): 169 start = start.tree 170 171 idx = start.parent.children.index(start) 172 if idx > 0: 173 for node in start.parent.children[idx - 1 :: -1]: 174 if condition is not None: 175 if check(node, condition, strict=strict): 176 return node 177 else: 178 return node 179 return None
Find the first sibling node before the given node. If a condition is applied then it will be the first sibling node that passes that condition.
Args
- start (All_Nodes): The node to find the previous sibling from.
- condition (Optional[Test]): The test that is applied to each node.
Returns
Optional[All_Nodes]: The first node before the given node or None if no prior siblings.
210def find_all_between( 211 parent: Root | Element | AST, 212 start: Optional[int] = 0, 213 end: Optional[int] = 0, 214 condition: Optional[Test] = None, 215 _range: Optional[slice] = None, 216 strict: bool = True, 217) -> list[All_Nodes]: 218 """Find all sibling nodes in parent that meet the provided condition from start index 219 to end index. 220 221 Args: 222 parent (Root | Element): The parent element to get nodes from. 223 start (int, optional): The starting index, inclusive. Defaults to 0. 224 end (int, optional): The ending index, exclusive. Defaults to 0. 225 condition (Test, optional): Condition to apply to each node. Defaults to None. 226 _range (slice, optional): Slice to apply to the parent nodes children instead of start and 227 end indecies. Defaults to None. 228 229 Returns: 230 list[All_Nodes]: List of all matching nodes or an empty list if none were found. 231 """ 232 if isinstance(parent, AST): 233 parent = parent.tree 234 235 if _range is not None: 236 start = _range.start 237 end = _range.stop 238 239 results = [] 240 if start in range(0, end) and end in range(start, len(parent.children) + 1): 241 for node in parent.children[start:end]: 242 if condition is not None: 243 if check(node, condition, strict=strict): 244 results.append(node) 245 else: 246 results.append(node) 247 return results
Find all sibling nodes in parent that meet the provided condition from start index to end index.
Args
- parent (Root | Element): The parent element to get nodes from.
- start (int, optional): The starting index, inclusive. Defaults to 0.
- end (int, optional): The ending index, exclusive. Defaults to 0.
- condition (Test, optional): Condition to apply to each node. Defaults to None.
- _range (slice, optional): Slice to apply to the parent nodes children instead of start and
- end indecies. Defaults to None.
Returns
list[All_Nodes]: List of all matching nodes or an empty list if none were found.