如何为非有效XML文件生成闭合节点并按规则补全<sec>标签?
Hey there! Let's break down your two problems step by step—fixing unclosed XML nodes and adding hierarchical closing <sec> tags based on their id attributes.
1. Generating Closing Nodes for Invalid XML
Strict XML parsers will reject files with unclosed tags outright, so your first move is to use a tolerant parser that can recover and fix incomplete structures. Here's a practical approach using Python's lxml library, which has built-in recovery capabilities:
Example Code
from lxml import etree # Load your invalid XML file with open("invalid.xml", "r") as f: invalid_xml = f.read() # Parse with recovery mode enabled parser = etree.XMLParser(recover=True) tree = etree.fromstring(invalid_xml.encode(), parser=parser) # Convert back to well-formed XML well_formed_xml = etree.tostring(tree, encoding="unicode", pretty_print=True) # Save the result with open("fixed.xml", "w") as f: f.write(well_formed_xml)
This will automatically add missing closing tags for most basic cases. For more edge cases (like malformed attribute values), you might need to pre-process the text to clean up obvious errors first.
2. Adding Closing <sec> Tags Based on ID Hierarchy
For your specific requirement of inserting </sec> tags before subsequent <sec> nodes based on the id hierarchy, here's a targeted solution. The core logic revolves around tracking the depth of each <sec> (from its dot-separated id) and calculating how many parent levels need to be closed when moving to a new <sec>.
Key Rules
Each id's depth is the number of dot-separated segments:
id="1"→ depth 1id="1.1"→ depth 2id="2.1.3"→ depth 3
When processing a new <sec>:
- Compare its depth to the previous
<sec>'s depth. - If the new depth is less than the previous: insert
(previous_depth - new_depth)closing tags. - If the new depth equals the previous: insert 1 closing tag (close the sibling).
- If the new depth is greater: no closing tags needed (it's a child of the previous
<sec>). - Don't forget to add closing tags for all remaining open
<sec>nodes at the end of the file.
Example Input
<sec id="1"> <sec id="1.1"> <sec id="1.2"> <sec id="2"> <sec id="2.1"> <sec id="2.1.1"> <sec id="3">
Expected Output
<sec id="1"> <sec id="1.1"> </sec> <sec id="1.2"> </sec> </sec> <sec id="2"> <sec id="2.1"> <sec id="2.1.1"> </sec> </sec> </sec> <sec id="3"> </sec>
Implementation Code (Python)
def fix_sec_closing_tags(input_path, output_path): with open(input_path, "r") as f: lines = [line.strip() for line in f if line.strip()] output = [] previous_depth = 0 for line in lines: if line.startswith("<sec id="): # Calculate current depth from id id_str = line.split('id="')[1].split('"')[0] current_depth = len(id_str.split(".")) # Add closing tags based on depth difference if previous_depth > 0: diff = previous_depth - current_depth if diff >= 0: # Add (diff + 1) closing tags if same depth, or diff if new is shallower close_count = diff + 1 if current_depth == previous_depth else diff output.extend(["</sec>"] * close_count) output.append(line) previous_depth = current_depth # Add closing tags for remaining open sec nodes output.extend(["</sec>"] * previous_depth) # Write the result with proper indentation with open(output_path, "w") as f: indent_level = 0 for line in output: if line.startswith("</sec>"): indent_level -= 1 f.write(" " * indent_level + line + "\n") if line.startswith("<sec id="): indent_level += 1 # Usage fix_sec_closing_tags("input.xml", "output.xml")
内容的提问来源于stack exchange,提问作者Don_B

