Skip to content

Commit 02b6da5

Browse files
authored
Merge pull request #9 from danlsn/8-add-xml-utilities-module
8 add xml utilities module
2 parents 96c6434 + 716f7c5 commit 02b6da5

3 files changed

Lines changed: 84 additions & 1 deletion

File tree

src/dander/__about__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# SPDX-FileCopyrightText: 2024-present Daniel Lawson <daniel.lawson@rmit.edu.au>
22
#
33
# SPDX-License-Identifier: MIT
4-
__version__ = "0.3.1"
4+
__version__ = "0.4.0"

src/dander/cli.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
import typer
55
from loguru import logger
66
import dander.io.json_utils as json_utils
7+
import dander.io.xml_utils as xml_utils
78

89
app = typer.Typer()
910
json_app = typer.Typer()
1011
app.add_typer(json_app, name="json")
12+
xml_app = typer.Typer()
13+
app.add_typer(xml_app, name="xml")
1114

1215

1316
@json_app.command("format")
@@ -55,6 +58,45 @@ def split_json_file(
5558
raise typer.Exit(code=1)
5659

5760

61+
@xml_app.command("format")
62+
def reformat_xml(
63+
file_path: str,
64+
*,
65+
strict: Annotated[
66+
bool,
67+
typer.Option(
68+
"--strict",
69+
"-s",
70+
help="Enforce strict-mode XML formatting, input file must be an XML file.",
71+
),
72+
] = True,
73+
indent: Annotated[
74+
int,
75+
typer.Option(
76+
"--indent",
77+
"-i",
78+
help="Number of spaces used per indentation level for XML formatting.",
79+
),
80+
] = 2,
81+
write_file: Annotated[
82+
bool,
83+
typer.Option("--write", "-w", help="Write formatted XML to file in-place."),
84+
] = False,
85+
verbose: Annotated[
86+
bool, typer.Option("--verbose", "-v", help="Print formatted XML to console.")
87+
] = False,
88+
):
89+
logger.add(
90+
sys.stderr,
91+
format="{time} {level} {message}",
92+
filter="my_module",
93+
level="DEBUG" if verbose else "INFO",
94+
)
95+
xml_utils.reformat_xml_file(
96+
file_path, strict=strict, indent=indent, write_file=write_file, verbose=verbose
97+
)
98+
99+
58100
@app.command()
59101
def basename(file_path: Path = None):
60102
"""

src/dander/io/xml_utils.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
from xml.dom import minidom
2+
from pathlib import Path
3+
from loguru import logger
4+
5+
6+
def pretty_print_xml(xml: str, indent: int = 2):
7+
reparsed = minidom.parseString(xml)
8+
return reparsed.toprettyxml(indent=" " * indent)
9+
10+
11+
def get_xml_file_contents(file_path: str, strict: bool = True):
12+
file_path = Path(file_path)
13+
if not file_path.is_file():
14+
raise FileNotFoundError(f"File not found: {file_path}")
15+
if strict and not file_path.suffix == ".xml":
16+
raise ValueError(f"File is not an XML file: {file_path}")
17+
with file_path.open() as f:
18+
return f.read()
19+
20+
21+
def reformat_xml_file(
22+
file_path: str,
23+
strict: bool = True,
24+
indent: int = 2,
25+
write_file: bool = False,
26+
verbose: bool = False,
27+
):
28+
"""Reformat an XML file. Optionally write in-place or print to console."""
29+
xml_file_path = Path(file_path)
30+
xml_file_content = get_xml_file_contents(file_path, strict=strict)
31+
xml_data = pretty_print_xml(xml_file_content, indent=indent)
32+
logger.debug(
33+
f"Reformatted XML file: {xml_file_path.name} (strict={strict}, indent={indent})"
34+
)
35+
36+
if not write_file or verbose:
37+
logger.debug("Printing formatted XML to console")
38+
rich.print(xml_data)
39+
else:
40+
logger.debug("Writing formatted XML to file in-place")
41+
xml_file_path.write_text(xml_data)

0 commit comments

Comments
 (0)