# HG changeset patch # User Andreas Nolda # Date 1587837971 -7200 # Sat Apr 25 20:06:11 2020 +0200 # Node ID feeb9e97dbc32c6eb821503aaf6ff2e628a11327 # Parent 575f62e2de0f86968dd4eaa8a6bc03521267e61f add option "-M" ("--files-and-matches") diff --git a/ChangeLog.md b/ChangeLog.md --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,8 @@ +2020-04-25: + +* add option `-M` (`--files-and-matches`) +* bump version to 2.8 + 2020-04-24: * rename option `-n` (`--declare-ns`) to `-N` diff --git a/README.md b/README.md --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ [-l] [--files-with-matches] [-L] [--files-without-match] [-m] [--matches] + [-M] [--files-and-matches] [-n] [--line-number] [-N] [--declare-ns] [-q] [--quiet] @@ -39,14 +40,14 @@ xgrep.py [-h] [--help] Normally, `xgrep.py` outputs the matching parts of the XML files together with -their file names and the XPath expression. If `-r ` is set, the +their file names and the XPath expression. The option `-m` outputs only the +matching parts, without file names or XPath expressions; with `-M`, the matching +parts are prefixed with the corresponding file name. If `-r ` is set, the [EXSLT function `:test()`](http://exslt.org/regexp/functions/test/) can be -used in the XPath expression for matching regular expressions. The option `-m` -outputs only the matching parts, without file names or XPath expressions. The -option `-i` indents the matching parts, and the option `-N` includes namespace -declarations. The `-C` option preserves color and formatting codes when piping -output through [GNU less](http://www.gnu.org/software/less/) and similar -programs. +used in the XPath expression for matching regular expressions. The option `-i` +indents the matching parts, and the option `-N` includes namespace declarations. +The `-C` option preserves color and formatting codes when piping output through +[GNU less](http://www.gnu.org/software/less/) and similar programs. The options `-c`, `-l`, `-L`, `-n`, and `-q` mimic the behaviour of [GNU grep](http://www.gnu.org/software/grep/). The latter option suppresses any diff --git a/xgrep.py b/xgrep.py --- a/xgrep.py +++ b/xgrep.py @@ -1,6 +1,6 @@ #! /usr/bin/python3 # xgrep.py -- search for elements in XML files, using XPath 1.0 expressions -# Andreas Nolda 2020-04-24 +# Andreas Nolda 2020-04-25 import sys import argparse @@ -8,7 +8,7 @@ from blessings import Terminal from lxml import etree -version=2.7 +version=2.8 parser = argparse.ArgumentParser() parser.add_argument("expr", @@ -27,6 +27,8 @@ help="output list of non-matching files") parser.add_argument("-m", "--matches", action="store_true", help="output list of matches") +parser.add_argument("-M", "--files-and-matches", action="store_true", + help="output list of files and matches") parser.add_argument("-n", "--line-number", action="store_true", help="output line number of match start") parser.add_argument("-N", "--declare-ns", action="store_true", @@ -84,36 +86,77 @@ string = re.sub('\s+xmlns(:[A-Za-z_][A-Za-z0-9._-]*)?="[^"]+"', '', match) return string -def print_filename(file, int): - if args.count: - print(term.bold(file) + ":{0}".format(int)) - else: - print(term.bold(file)) +def print_filename(file, end): + print(term.bold(file), end=end) + +def print_total(matches, end): + print(len(matches), end=end) + +def print_expr(expr, end): + print(term.bold(expr), end=end) -def print_match(match, int): - if not args.matches: - if args.count: - print(term.bold("{0}[{1}]".format(args.expr, int)) + ":") - else: - print(term.bold(args.expr) + ":") - if args.line_number: - print(term.bright_black("{0}".format(match.sourceline)) + ":", end="") +def print_index(int, end): + print(term.bold("[{0}]".format(int + 1)), end=end) + +def print_line_number(match, end): + print(term.bright_black("{0}".format(match.sourceline)), end=end) + +def print_match(match, end): if args.declare_ns: - print(serialize_match(match)) + print(serialize_match(match), end=end) else: - print(remove_ns(serialize_match(match))) + print(remove_ns(serialize_match(match)), end=end) def print_matches(matches, file): if matches: - if not args.matches: - print_filename(file, len(matches)) - if not args.files_with_matches: + if args.files_with_matches: + if args.count: + print_filename(file, ":") + print_total(matches, "\n") + else: + print_filename(file, "\n") + elif args.matches: + for i, match in enumerate(matches): + if args.count: + print_index(i, ":") + if args.line_number: + print_line_number(match, ":") + print_match(match, "\n") + elif args.files_and_matches: for i, match in enumerate(matches): - print_match(match, i + 1) + if args.count: + print_filename(file, "") + print_index(i, ":") + else: + print_filename(file, ":") + if args.line_number: + print_line_number(match, ":") + print_match(match, "\n") + else: + if args.count: + print_filename(file, ":") + print_total(matches, "\n") + for i, match in enumerate(matches): + print_expr(args.expr, "") + print_index(i, ":\n") + if args.line_number: + print_line_number(match, ":") + print_match(match, "\n") + else: + print_filename(file, "\n") + for i, match in enumerate(matches): + print_expr(args.expr, ":\n") + if args.line_number: + print_line_number(match, ":") + print_match(match, "\n") def print_nonmatches(matches, file): if not matches: - print_filename(file, len(matches)) + if args.count: + print_filename(file, ":") + print_total(matches, "\n") + else: + print_filename(file, "\n") def main(): n = 0