Create a SAX parser that tracks line and column numbers for each element. Monkey patches the SAX content handler to store the current line and column position from the underlying expat parser onto each element as a parse_position attribute (line, column) tuple. Returns:
()
| 344 | |
| 345 | |
| 346 | def _create_line_tracking_parser(): |
| 347 | """ |
| 348 | Create a SAX parser that tracks line and column numbers for each element. |
| 349 | |
| 350 | Monkey patches the SAX content handler to store the current line and column |
| 351 | position from the underlying expat parser onto each element as a parse_position |
| 352 | attribute (line, column) tuple. |
| 353 | |
| 354 | Returns: |
| 355 | defusedxml.sax.xmlreader.XMLReader: Configured SAX parser |
| 356 | """ |
| 357 | |
| 358 | def set_content_handler(dom_handler): |
| 359 | def startElementNS(name, tagName, attrs): |
| 360 | orig_start_cb(name, tagName, attrs) |
| 361 | cur_elem = dom_handler.elementStack[-1] |
| 362 | cur_elem.parse_position = ( |
| 363 | parser._parser.CurrentLineNumber, # type: ignore |
| 364 | parser._parser.CurrentColumnNumber, # type: ignore |
| 365 | ) |
| 366 | |
| 367 | orig_start_cb = dom_handler.startElementNS |
| 368 | dom_handler.startElementNS = startElementNS |
| 369 | orig_set_content_handler(dom_handler) |
| 370 | |
| 371 | parser = defusedxml.sax.make_parser() |
| 372 | orig_set_content_handler = parser.setContentHandler |
| 373 | parser.setContentHandler = set_content_handler # type: ignore |
| 374 | return parser |