Skip to content

Commit

Permalink
transform: honor --file with a non-XML result.
Browse files Browse the repository at this point in the history
  • Loading branch information
peteradrichem committed Dec 25, 2024
1 parent 12f2734 commit 5e722e2
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 45 deletions.
14 changes: 11 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,22 @@ Xul -- XML Utilities
:target: https://pypi.org/project/Xul/
:alt: Python versions

.. image:: https://readthedocs.org/projects/xul/badge/?version=latest
:target: https://xul.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status
.. image:: https://img.shields.io/pypi/l/xul.svg
:target: https://pypi.org/project/Xul/
:alt: License

.. image:: https://img.shields.io/pypi/v/xul
:target: https://pypi.org/project/Xul/
:alt: PyPI version

.. image:: https://img.shields.io/pypi/wheel/xul.svg
:target: https://pypi.org/project/Xul/
:alt: Wheel

.. image:: https://readthedocs.org/projects/xul/badge/
:target: https://xul.readthedocs.io/en/stable/
:alt: Documentation

Xul is a set of XML scripts written in Python.
Documentation can be found on `Read The Docs`_.

Expand Down
9 changes: 5 additions & 4 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ Changelog

This document records all notable changes to `Xul <https://xul.readthedocs.io/>`_.

`Unreleased <https://github.com/peteradrichem/Xul/compare/2.4.2...main>`_ (2024-12-XX)
--------------------------------------------------------------------------------------
* Documentation updates
* Tested on Python 3.11, 3.12, 3.13
`2.5.0 <https://github.com/peteradrichem/Xul/compare/2.4.2...2.5.0>`_ (2024-12-25)
----------------------------------------------------------------------------------
* Documentation updates.
* Tested on Python 3.11, 3.12, 3.13.
* :doc:`transform <transform>`: honor ``--file`` with a non-XML result.

`2.4.2 <https://github.com/peteradrichem/Xul/compare/2.4.1...2.4.2>`_ (2024-12-15)
----------------------------------------------------------------------------------
Expand Down
12 changes: 8 additions & 4 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ Current version: |release|
:target: https://pypi.org/project/Xul/
:alt: Python versions

.. image:: https://img.shields.io/pypi/wheel/xul.svg
:target: https://pypi.org/project/Xul/
:alt: Wheel

.. image:: https://img.shields.io/pypi/l/xul.svg
:target: https://pypi.org/project/Xul/
:alt: License
Expand All @@ -21,6 +17,14 @@ Current version: |release|
:target: https://pypi.org/project/Xul/
:alt: PyPI version

.. image:: https://img.shields.io/pypi/wheel/xul.svg
:target: https://pypi.org/project/Xul/
:alt: Wheel

.. image:: https://readthedocs.org/projects/xul/badge/
:target: https://xul.readthedocs.io/en/stable/
:alt: Documentation

.. index::
single: scripts

Expand Down
2 changes: 1 addition & 1 deletion src/xul/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"""

# Xul version.
__version_info__ = ("2", "5", "0-beta")
__version_info__ = ("2", "5", "0")
__version__ = ".".join(__version_info__)
79 changes: 46 additions & 33 deletions src/xul/cmd/transform.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
# -*- coding: utf-8 -*-

"""Transform XML source with XSLT."""


from __future__ import print_function

from argparse import ArgumentParser, FileType
import sys
import errno
import sys
from argparse import ArgumentParser, FileType

# pylint: disable=no-name-in-module
# lxml ElementTree <https://lxml.de/>
Expand All @@ -21,29 +18,39 @@

def parse_cl():
"""Parse the command line for options, XSLT source and XML sources."""
parser = ArgumentParser(
description=__doc__)
parser.add_argument(
"-V", "--version", action="version",
version="%(prog)s " + __version__)
parser = ArgumentParser(description=__doc__)
parser.add_argument("-V", "--version", action="version", version="%(prog)s " + __version__)
parser.add_argument("xslt_source", help="XSLT source (file, http://...)")
parser.add_argument(
"xml_source", nargs='?', default=sys.stdin, type=FileType('r'),
help="XML source (file, <stdin>, http://...)")
"xml_source",
nargs="?",
default=sys.stdin,
type=FileType("r"),
help="XML source (file, <stdin>, http://...)",
)
output_group = parser.add_mutually_exclusive_group(required=False)
output_group.add_argument(
"-x", "--xsl-output", action="store_true", default=False,
dest="xsl_output", help="honor xsl:output")
"-x",
"--xsl-output",
action="store_true",
default=False,
dest="xsl_output",
help="honor xsl:output",
)
output_group.add_argument(
"-o", "--omit-declaration", action="store_false", default=True,
dest="declaration", help="omit the XML declaration")
parser.add_argument(
"-f", "--file", dest="file", help="save result to file")
"-o",
"--omit-declaration",
action="store_false",
default=True,
dest="declaration",
help="omit the XML declaration",
)
parser.add_argument("-f", "--file", dest="file", help="save result to file")
return parser.parse_args()


def print_result(result):
"""Print transformation result."""
"""Print transformation result (catch lookup errors)."""
try:
print(result)
# io.TextIOWrapper catches Python 3 BrokenPipeError.
Expand All @@ -53,7 +60,7 @@ def print_result(result):
sys.stderr.write("IOError: %s [%s]\n" % (e.strerror, e.errno))
except LookupError as e:
# LookupError: unknown encoding: UCS-4.
sys.stderr.write("LookupError (XSLT result): %s\n" % e)
sys.stderr.write("Cannot print XSLT result (LookupError): %s\n" % e)


def save_to_file(result, target_file):
Expand All @@ -67,8 +74,7 @@ def save_to_file(result, target_file):
with open(target_file, file_mode) as file_object:
file_object.write(result)
except EnvironmentError as e:
sys.stderr.write("Saving result to %s failed: %s\n" % (
target_file, e.strerror))
sys.stderr.write("Saving result to %s failed: %s\n" % (target_file, e.strerror))
sys.exit(80)


Expand All @@ -82,16 +88,21 @@ def output_xslt(xml_source, transformer, parser, args):
"""
result = xml_transformer(xml_source, transformer, parser)
if not result:
pass
elif result.getroot() is None:
return None

if result.getroot() is None:
# Result is not an ElementTree.
print(result)
if args.file:
save_to_file(result, args.file)
else:
print(result)
return None

# https://lxml.de/xpathxslt.html#xslt-result-objects
# https://lxml.de/api/lxml.etree._XSLTResultTree-class.html
# https://lxml.de/apidoc/lxml.etree.html#lxml.etree._XSLTResultTree
# _XSLTResultTree (./src/lxml/xslt.pxi):
elif args.xsl_output:
# https://lxml.de/api/lxml.etree.XSLT-class.html
if args.xsl_output:
# https://lxml.de/apidoc/lxml.etree.html#lxml.etree.XSLT
# XSLT.tostring(). Deprecated: use str(result_tree) instead.
#
# Python 2: str(_XSLTResultTree) == bytes(_XSLTResultTree).
Expand All @@ -111,8 +122,8 @@ def output_xslt(xml_source, transformer, parser, args):
# a declaration as needed that reflects the encoding of the returned string.
else:
etree_result = tostring(
result, encoding=result.docinfo.encoding,
xml_declaration=args.declaration)
result, encoding=result.docinfo.encoding, xml_declaration=args.declaration
)
if args.file:
save_to_file(etree_result, args.file)
else:
Expand All @@ -122,9 +133,11 @@ def output_xslt(xml_source, transformer, parser, args):
etree_result = etree_result.decode(result.docinfo.encoding)
print_result(etree_result)

return None


def main():
"""transform command line script entry point."""
"""Entry point for command line script transform."""
# Logging to the console.
setup_logger_console()

Expand All @@ -136,10 +149,10 @@ def main():
# Build an XSL Transformer from an XSLT source.
transformer = build_xsl_transform(args.xslt_source)
if not transformer:
sys.stderr.write('Invalid XSLT source specified\n')
sys.stderr.write("Invalid XSLT source specified\n")
sys.exit(60)
else:
sys.stderr.write('No XSLT source specified\n')
sys.stderr.write("No XSLT source specified\n")
sys.exit(50)

# Initialise XML parser.
Expand Down

0 comments on commit 5e722e2

Please sign in to comment.