phml.locate.find
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.travel.travel import path, walk 10from phml.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: All_Nodes, 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 109 if not isinstance(start, (AST, Root)): 110 idx = start.parent.children.index(start) 111 if len(start.parent.children) - 1 > idx: 112 for node in start.parent.children[idx + 1 :]: 113 if condition is not None: 114 if check(node, condition, strict=strict): 115 return node 116 else: 117 return node 118 return None 119 120 121def find_all_after( 122 start: Element, 123 condition: Optional[Test] = None, 124 strict: bool = True, 125) -> list[All_Nodes]: 126 """Get all sibling nodes that match the condition. 127 128 Args: 129 start (All_Nodes): Node to get siblings from. 130 condition (Test): Condition to check against each node. 131 132 Returns: 133 list[All_Nodes]: Returns the all siblings that match the 134 condition or an empty list if none were found. 135 """ 136 idx = start.parent.children.index(start) 137 matches = [] 138 139 if len(start.parent.children) - 1 > idx: 140 for node in start.parent.children[idx + 1 :]: 141 if condition is not None: 142 if check(node, condition, strict=strict): 143 matches.append(node) 144 else: 145 matches.append(node) 146 147 return matches 148 149 150def find_before( 151 start: All_Nodes, 152 condition: Optional[Test] = None, 153 strict: bool = True, 154) -> Optional[All_Nodes]: 155 """Find the first sibling node before the given node. If a condition is applied 156 then it will be the first sibling node that passes that condition. 157 158 Args: 159 start (All_Nodes): The node to find the previous sibling from. 160 condition (Optional[Test]): The test that is applied to each node. 161 162 Returns: 163 Optional[All_Nodes]: The first node before the given node 164 or None if no prior siblings. 165 """ 166 167 if not isinstance(start, (AST, Root)): 168 idx = start.parent.children.index(start) 169 if idx > 0: 170 for node in start.parent.children[idx - 1 :: -1]: 171 if condition is not None: 172 if check(node, condition, strict=strict): 173 return node 174 else: 175 return node 176 return None 177 178 179def find_all_before( 180 start: Element, 181 condition: Optional[Test] = None, 182 strict: bool = True, 183) -> list[All_Nodes]: 184 """Find all nodes that come before the given node. 185 186 Args: 187 start (All_Nodes): The node to find all previous siblings from. 188 condition (Optional[Test]): The condition to apply to each node. 189 190 Returns: 191 list[All_Nodes]: A list of nodes that come before the given node. 192 Empty list if no nodes were found. 193 """ 194 idx = start.parent.children.index(start) 195 matches = [] 196 197 if idx > 0: 198 for node in start.parent.children[:idx]: 199 if condition is not None: 200 if check(node, condition, strict=strict): 201 matches.append(node) 202 else: 203 matches.append(node) 204 return matches 205 206 207def find_all_between( 208 parent: Root | Element | AST, 209 start: Optional[int] = 0, 210 end: Optional[int] = 0, 211 condition: Optional[Test] = None, 212 _range: Optional[slice] = None, 213 strict: bool = True, 214) -> list[All_Nodes]: 215 """Find all sibling nodes in parent that meet the provided condition from start index 216 to end index. 217 218 Args: 219 parent (Root | Element): The parent element to get nodes from. 220 start (int, optional): The starting index, inclusive. Defaults to 0. 221 end (int, optional): The ending index, exclusive. Defaults to 0. 222 condition (Test, optional): Condition to apply to each node. Defaults to None. 223 _range (slice, optional): Slice to apply to the parent nodes children instead of start and 224 end indecies. Defaults to None. 225 226 Returns: 227 list[All_Nodes]: List of all matching nodes or an empty list if none were found. 228 """ 229 if isinstance(parent, AST): 230 parent = parent.tree 231 232 if _range is not None: 233 start = _range.start 234 end = _range.stop 235 236 results = [] 237 if start in range(0, end) and end in range(start, len(parent.children) + 1): 238 for node in parent.children[start:end]: 239 if condition is not None: 240 if check(node, condition, strict=strict): 241 results.append(node) 242 else: 243 results.append(node) 244 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.
Arguments:
- *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.
Arguments:
- 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.
Arguments:
- 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: All_Nodes, 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 110 if not isinstance(start, (AST, Root)): 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
Get the first sibling node following the provided node that matches the condition.
Arguments:
- 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.
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
Get all sibling nodes that match the condition.
Arguments:
- 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.
180def find_all_before( 181 start: Element, 182 condition: Optional[Test] = None, 183 strict: bool = True, 184) -> list[All_Nodes]: 185 """Find all nodes that come before the given node. 186 187 Args: 188 start (All_Nodes): The node to find all previous siblings from. 189 condition (Optional[Test]): The condition to apply to each node. 190 191 Returns: 192 list[All_Nodes]: A list of nodes that come before the given node. 193 Empty list if no nodes were found. 194 """ 195 idx = start.parent.children.index(start) 196 matches = [] 197 198 if idx > 0: 199 for node in start.parent.children[:idx]: 200 if condition is not None: 201 if check(node, condition, strict=strict): 202 matches.append(node) 203 else: 204 matches.append(node) 205 return matches
Find all nodes that come before the given node.
Arguments:
- 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.
151def find_before( 152 start: All_Nodes, 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 168 if not isinstance(start, (AST, Root)): 169 idx = start.parent.children.index(start) 170 if idx > 0: 171 for node in start.parent.children[idx - 1 :: -1]: 172 if condition is not None: 173 if check(node, condition, strict=strict): 174 return node 175 else: 176 return node 177 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.
Arguments:
- 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.
208def find_all_between( 209 parent: Root | Element | AST, 210 start: Optional[int] = 0, 211 end: Optional[int] = 0, 212 condition: Optional[Test] = None, 213 _range: Optional[slice] = None, 214 strict: bool = True, 215) -> list[All_Nodes]: 216 """Find all sibling nodes in parent that meet the provided condition from start index 217 to end index. 218 219 Args: 220 parent (Root | Element): The parent element to get nodes from. 221 start (int, optional): The starting index, inclusive. Defaults to 0. 222 end (int, optional): The ending index, exclusive. Defaults to 0. 223 condition (Test, optional): Condition to apply to each node. Defaults to None. 224 _range (slice, optional): Slice to apply to the parent nodes children instead of start and 225 end indecies. Defaults to None. 226 227 Returns: 228 list[All_Nodes]: List of all matching nodes or an empty list if none were found. 229 """ 230 if isinstance(parent, AST): 231 parent = parent.tree 232 233 if _range is not None: 234 start = _range.start 235 end = _range.stop 236 237 results = [] 238 if start in range(0, end) and end in range(start, len(parent.children) + 1): 239 for node in parent.children[start:end]: 240 if condition is not None: 241 if check(node, condition, strict=strict): 242 results.append(node) 243 else: 244 results.append(node) 245 return results
Find all sibling nodes in parent that meet the provided condition from start index to end index.
Arguments:
- 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.