fix(xml): honor explicit encodings when extracting text (#4572)
`partition_xml(encoding=...)` was ignored when extracting text (the
default), so a Windows-1252 XML upload without an encoding declaration
failed with `XMLSyntaxError` even when the caller supplied the correct
encoding. Pass the encoding through to the streaming parser for file
inputs and XPath selections, preserving XML encoding detection when
omitted and leaving already-decoded `text` inputs unchanged.
The parser also needs to accept Python's `utf-8-sig` codec name.
Normalize that codec and its aliases to an explicit `UTF-8` override, so
BOM-present and BOM-absent inputs work even with a conflicting XML
declaration. Other names stay unchanged, including names such as `UCS-4`
that libxml2 accepts but Python does not. Unknown names still raise the
parser's error. Entity resolution and spool handling are unchanged, and
caller-owned streams remain open.
The original propagation regression:
```python
from io import BytesIO
from unstructured.partition.xml import partition_xml
payload = "<root><item>Café</item></root>".encode("windows-1252")
elements = partition_xml(file=BytesIO(payload), encoding="windows-1252")
assert [element.text for element in elements] == ["Café"]
```
Validation on Windows / Python 3.12.8:
- Final XML module: **92 passed**, **100% statement coverage**. Cases
cover paths, file handles, BytesIO, rolled spools, XPath, legacy
encodings, `utf-8-sig` / `utf_8_sig` with and without a BOM, conflicting
declarations, stream ownership, and libxml2-only/unknown encoding names.
- Before the codec-name follow-up, these tests yield **40 failed, 52
passed** against the reviewed commit `7eedef6`.
- XML, JSON/NDJSON and encoding regression suites: **448 passed, 3
failed**. Loading the unmodified XML implementation from current main
`5618dca` in memory and rerunning the five adjacent suites reproduces
all three failures (**356 passed, 3 failed**): two recursion-depth
error-message assertions and file-type detection without libmagic. The
full repository suite and Linux CI matrix were not run locally.
- Repository-wide Ruff lint and format checks (353 files) and all
applicable pre-commit hooks pass. The version-sync check passes on an
otherwise identical LF copy; the original Windows checkout reports only
a CRLF/LF difference. The existing dev version is unchanged.
The codec-name follow-up addresses the P2 review on this PR. The branch
is also merged with main at `5618dca`; upstream changes and the current
`0.27.34-dev6` version are retained. The original issue/PR search found
no overlapping fix for encoding propagation; #4560 addresses
mixed-content ordering and missing tail text separately.
AI assistance: OpenAI Codex investigated, implemented and ran the local
checks, and drafted this description.
<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/Unstructured-IO/unstructured/pull/4572?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="View guided diff"
src="https://www.cubic.dev/buttons/review-in-cubic-light.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
---------
Signed-off-by: JackyHsu-X <xv1070733106@gmail.com>