@@ 27,6 27,7 @@ Usage:
[-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 @@ Usage:
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 <ns>` 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 <ns>` is set, the
[EXSLT function `<ns>: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
@@ 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 @@ import re
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 @@ parser.add_argument("-L", "--files-witho
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 @@ def remove_ns(match):
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