使用安全的 Python 腳本快速分割大型 XML 文件

要快速拆分大型 XML 文件,應該按完整的重複記錄進行分割,而不是按位元組剪切文件。以下範例使用 Python 標準函式庫來串流輸入,並寫入具有相同根元素和根屬性的獨立 XML 文件。此範例適用於常見的結構,例如 `<a>` <records><record>...</record><record>...</record></records>,其中根元素的每個直接子元素都是一個獨立的記錄。

XML 編輯器顯示記錄根,其中包含重複的記錄元素,以及一個放大的記錄,其中包含 ID、名稱和值子項目。
在根目錄下重複的直接子記錄處進行分割;任意位元組邊界可能會破壞 XML 標記。

選擇一個安全的分割點

一個 XML 文件包含一個文檔元素,且其標籤必須正確嵌套。原始的檔案分割器可能會截斷起始標籤、巢狀記錄,甚至字元編碼序列,從而留下不屬於獨立 XML 的片段。 W3C XML 規格詳細解釋了格式良好的文件和根元素規則。

在拆分前,請檢查文件並識別重複的記錄元素。此腳本會將根元素下的所有直接子元素視為一個整體。只有當這些子元素是獨立的記錄,且根元素本身不包含任何必須出現在特定位置的有意義的混合文字或元資料時才使用此腳本。如果記錄嵌套了多層,請使用專為該 XML 詞彙表設計的分割器,而不是盲目地修改腳本。

Split That XML / OOXP Splitter 怎麼樣?

原文引導讀者使用 Split That XML。其SourceForge 專案頁面仍然描述了該工具,但顯示其最後更新日期為 2015 年 9 月 27 日。請將其視為舊版軟體:其聲稱的與舊版 Windows 相容並不能保證在當前系統上也能正常運作。如果您已經擁有該軟體的副本,請在副本上進行操作,並在使用前驗證輸出結果。

使用 Python 拆分記錄

Python 會xml.etree.ElementTree.iterparse()以增量方式讀取文檔,避免一次性將整個 XML 樹載入到記憶體中。下面的腳本將直接子元素分組,然後將每個批次寫入原始根標籤及其屬性的新副本中。它不需要任何第三方軟體包。如果尚未安裝 Python,請使用官方的Windows 版 Python 下載;ElementTree 文件中描述了此處使用的解析器。

工作資料夾包含 input.xml 和 split_xml.py,XML 原始碼在文字編輯器中開啟。
保持原始檔案不變,每次運行都選擇一個新的、空的輸出資料夾。
  1. 建立來源 XML 的工作副本。建立一個新的空輸出資料夾,例如parts.
  2. 在純文字編輯器中,將以下內容儲存split_xml.py到與副本相同的工作資料夾中。
from pathlib import Path
import sys
import xml.etree.ElementTree as ET

source = Path(sys.argv[1])
out_dir = Path(sys.argv[2])
records_per_file = int(sys.argv[3]) if len(sys.argv) > 3 else 500

if records_per_file < 1:
    raise SystemExit("records_per_file must be at least 1")
out_dir.mkdir(parents=True, exist_ok=True)
if any(out_dir.glob("part_*.xml")):
    raise SystemExit("Choose a new, empty output folder first")

records = []
part_count = 0
root = None
root_tag = None
root_attrib = {}

def write_part(items, number):
    wrapper = ET.Element(root_tag, root_attrib)
    wrapper.extend(items)
    target = out_dir / f"part_{number:04d}.xml"
    ET.ElementTree(wrapper).write(
        target, encoding="utf-8", xml_declaration=True
    )

depth = 0
for event, elem in ET.iterparse(source, events=("start", "end")):
    if event == "start":
        depth += 1
        if depth == 1:
            root = elem
            root_tag = elem.tag
            root_attrib = dict(elem.attrib)
    else:
        if depth == 2:
            records.append(elem)
            if len(records) == records_per_file:
                part_count += 1
                write_part(records, part_count)
                records.clear()
                root[:] = []
        depth -= 1

if records:
    part_count += 1
    write_part(records, part_count)
if part_count == 0:
    raise SystemExit("No direct-child elements were found under the root")
print(f"Wrote {part_count} files.")

運行該命令

在工作資料夾中開啟 PowerShell,並檢查 Python 是否可用。最後一個參數是每個部分的記錄數;如果省略,則預設值為 500。

python --version
python split_xml.py input.xml parts 500

在安裝了 Python 啟動器的 Windows 系統中,第二行可以是py -3 split_xml.py input.xml parts 500`.`。該腳本會寫入諸如 `.` 之類的文件,part_0001.xml並報告已建立的文件數量。每次都使用空的輸出資料夾;如果匹配的部件檔案已存在,則腳本會停止執行,因此不會將新運行的檔案與先前的檔案混在一起。

Windows PowerShell 視窗顯示了將 input.xml 拆分為每個部分 500 個記錄的命令。
第三個指令參數設定的是記錄數,而不是保證的最大檔案大小。

導入前請檢查結果。

首先,解析產生的每個部分以捕獲格式錯誤的 XML。在 PowerShell 中執行:

python -c "import glob, xml.etree.ElementTree as ET; files=glob.glob('parts/*.xml'); [ET.parse(p) for p in files]; print(f'{len(files)} files parsed')"

確認報告的數字不為零,檢查幾個文件,並將總記錄數與來源記錄數進行比較。解析成功僅證明某個部分格式良好,並不證明它符合 XML 模式 (XSD)、DTD、業務規則或將要使用它的應用程式的要求。如果這些要求至關重要,請使用目標系統使用的模式或驗證器來驗證每個部分。 W3C XML 模式資源解釋了模式約束的獨立作用。

部件資料夾列出了三個 XML 部件文件,位於用於檢查輸出的命令提示字元上方。
解析每個部分以檢查其格式是否正確,然後分別執行應用程式的架構或匯入檢查。

限制和快速修復

  • 某個部分仍然過大:請減少記錄數,例如從 500 減少到 100。單一較大的記錄仍然可能導致某個部分超過目標大小;此腳本不強制執行嚴格的兆位元組上限。
  • 這些部分未通過模式驗證:請驗證所選記錄邊界是否符合模式所需的結構和順序。拆分操作可以保留格式良好的嵌套,但無法保留文件層級的有效性。
  • 前綴或格式已更改: ElementTree 可能以不同的方式序列化命名空間前綴,並規範化 XML 表示。請比較解析後的值和應用程式行為,而不是期望逐字節複製。
  • 原始檔使用了 DTD、註解、處理指令或根級元資料:這個簡單的腳本無法保留所有文件級結構。請使用支援詞彙表的 XML 工具,並在副本上進行測試。

對於常規的獨立記錄列表,這種方法可以產生易於管理、可單獨解析的文件,而不會破壞父子關係。記錄結構和目標位置的驗證規則決定了產生的檔案是否也適用於您的工作流程。

留下評論

使用 FotoSketcher 將照片轉換為繪畫、素描和卡通

使用 FotoSketcher 將照片轉換為繪畫、素描和卡通

使用 FotoSketcher Studio 將照片轉換成繪畫、鉛筆素描或卡通。學習如何選擇效果、調整預覽、保存作品。

使用音訊標識符詳細分析和識別音訊文件

使用音訊標識符詳細分析和識別音訊文件

了解音訊標識符揭示的位元率、編碼器和標籤訊息,其傳統工作流程如何運作,以及當前哪些工具可以檢查文件或識別歌曲。

我的照片索引:一款適用於 Windows 的開源照片管理器。

我的照片索引:一款適用於 Windows 的開源照片管理器。

My Photo Index 是一款舊版 Windows 相片目錄管理工具,用於標記、評分和瀏覽本機影像。請查看其文件功能、相容性限制以及一個維護良好的替代方案。

使用屬性變更器變更檔案和資料夾屬性、日期和時間

使用屬性變更器變更檔案和資料夾屬性、日期和時間

學習如何使用屬性變更器安全地編輯 Windows 檔案屬性和時間戳記、更新 JPEG EXIF 照片日期以及預覽批次變更。

如何在 Windows 10 中為每個顯示器設定不同的桌布

如何在 Windows 10 中為每個顯示器設定不同的桌布

為每個 Windows 10 顯示器設定單獨的壁紙,識別顯示器,調整影像適應度,並解決缺少顯示器選擇的問題。

pViewer:一款極簡圖像檢視器和漫畫閱讀器

pViewer:一款極簡圖像檢視器和漫畫閱讀器

了解 pViewer 的功能、照片和漫畫模式的工作原理、應該下載哪個 Windows 版本,以及舊版和重寫版之間的差異。

如何在 Windows 7 和 8 中使用快速鍵切換到下一個桌面背景

如何在 Windows 7 和 8 中使用快速鍵切換到下一個桌面背景

設定 Windows 7 或 8 投影片放映,建立一個小型 VBScript 快捷方式,並指派鍵盤熱鍵來切換到下一張桌布。

NeoDownloader:設定參數並從網站批量下載圖片

NeoDownloader:設定參數並從網站批量下載圖片

學習如何建立 NeoDownloader 專案、選擇爬取範圍、設定映像過濾器和目標位置,以及查看批次下載。

XnConvert:批次應用特效和轉換影像格式

XnConvert:批次應用特效和轉換影像格式

使用 XnConvert 可以批次套用特效、調整照片大小和轉換影像格式。選擇輸出設定、預覽編輯效果並保護您的原始文件。

使用 ManicTime 追蹤工作時間和電腦使用情況

使用 ManicTime 追蹤工作時間和電腦使用情況

了解 ManicTime 如何追蹤應用程式使用情況、活躍時間和空閒時間以及文檔,然後將您的活動歷史記錄轉換為專案標籤和時間表。