使用源文件中的数据从 XML 文件中获取块

Get a block from an XML file using data from a source file

我修改了这个问题,因为我已经阅读了一些关于 XML 的内容。

我有一个包含 AuthNumbers 列表的文件源文件。 111222 111333 111444 etc.

我需要搜索该列表中的数字并在相应的 XML 文件中找到它们。 在 xml 文件中,该行的格式如下: <trpcAuthCode>111222</trpcAuthCode>

这可以使用 grep 轻松实现,但是我需要包含事务的整个块。

块开始于: <trans type="network sale" recalled="false"><trans type="network sale" recalled="false" rollback="true"> and/or 一些其他变体。实际上 <trans*> 如果可能的话会更好。

块以</trans>

结尾

它不需要优雅或高效。我只需要它工作。我怀疑有些交易正在退出,我需要一种快速的方法来审查那些没有被处理的交易。

如果有帮助,这里是 link 原始(已消毒)xml https://www.dropbox.com/s/cftn23tnz8uc9t8/main.xml?dl=0

以及我想提取的内容: https://www.dropbox.com/s/b2bl053nom4brkk/transaction_results.xml?dl=0

每个结果的大小会有所不同,因为每笔交易的长度可能会有很大差异,具体取决于购买的产品数量。在结果 xml 中,您看到我根据 trpcAuthCode 列表 111222,111333,111444.

提取了我需要的 xml

关于 XML 和 awk 问题,您经常会发现 XML 处理的专家们的评论(他们的声誉中 k 的评论) awk 很复杂或不够用。据我了解这个问题,个人 and/or 调试目的需要该脚本。为此,我的解决方案应该足够了,但请记住,它不适用于任何合法的 XML 文件。

根据您的描述,脚本草图为:

  1. 匹配到<trans*>开始录制

  2. 如果找到 <trpcAuthCode> 获取其内容并与列表进行比较。如果匹配,请记住输出块。

  3. 如果匹配到</trans>则停止录制。如果输出已启用打印记录块否则丢弃它。

因为我在 中做了类似的事情,这应该不会太难实现。

不过,还需要一项附加功能:将 AuthNumbers 数组输入脚本。由于一个意外的巧合,我今天早上才在SO: How to access an array in an awk, which is declared in a different awk in shell? (thanks to the comment of jas]中得知答案。

所以,把它放在一个脚本中 filter-trpcAuthCode.awk:

BEGIN {
  record = 0 # state for recording
  buffer = "" # buffer for recording
  found = 0 # state for found auth code
  # build temp. array from authCodes which has to be pre-defined
  split(authCodes, list, "\n")
  # build final array where values become keys
  for (i in list) authCodeList[list[i]]
  # for debugging: output of authCodeList
  print "<!-- authCodeList:"
  for (authCode in authCodeList) {
    print authCode
  }
  print "-->"
}

/<trans( [^>]*)?>/ {
  record = 1 # start recording
  buffer = "" # clear buffer
  found = 0 # reset state for found auth code
}

record {
  buffer = buffer"\n"[=10=] # record line (if recording is enabled)
}

record && /<trpcAuthCode>/ {
  # extract auth code
  authCode = gensub(/^.*>([^<]*)<\/trpcAuthCode.*$/, "\1", "g")
  # check whether auth code in authCodeList
  found = authCode in authCodeList
}

/<\/trans>/ {
  record = 0 # stop recording
  # print buffer if auth code has been found
  if (found) {
    print buffer
  }
}

备注:

  1. 我最初在 BEGINauthCodes 上应用 split() 时遇到了困难。这会生成一个数组,其中拆分值使用枚举键存储。因此,我寻找一种解决方案来使值本身成为数组的键。 (否则,in运算符不能用于搜索。)我在SO: Check if array contains value.

  2. 的接受答案中找到了一个优雅的解决方案
  3. 我将提议的模式 <trans*> 实现为 /<trans( [^>]*)?/,它甚至会匹配 <trans>(尽管 <trans> 似乎永远不会在没有属性的情况下发生)但是不是 <transSet>.


  4. buffer = buffer"\n"[=28=]
    将当前行附加到先前的内容。 [=29=] 包含没有换行符的行。因此,它必须重新插入。我是怎么做到的,缓冲区以换行符开头,但最后一行没有结尾。考虑到 print buffer 在文本末尾添加换行符,这对我来说很好。或者,上面的代码片段可以替换为
    buffer = buffer [=31=] "\n"
    甚至
    buffer = (buffer != "" ? buffer"\n" : "") [=32=].
    (这是一个品味问题。)

  5. 过滤后的文件只是打印到标准输出通道。它可能被重定向到一个文件。考虑到这一点,我将 additional/debug 输出格式化为 XML 注释。

  6. 如果您对 awk 有点熟悉,您可能会注意到我的脚本中没有任何 next 语句。这是故意的。换句话说,规则的顺序是精心选择的,使得一行可能被所有规则连续processed/affected。 (我测试了一个极端情况:
    <trans><trpcAuthCode>111222</trpcAuthCode></trans>
    甚至这个都被正确处理了。)

为了简化测试,我添加了一个包装器 bash 脚本 filter-trpcAuthCode.sh

#!/usr/bin/bash
# uncomment next line for debugging
#set -x
# check command line arguments
if [[ $# -ne 2 ]]; then
  echo "ERROR: Illegal number of command line arguments!"
  echo ""
  echo "Usage:"
  echo $(basename [=11=]) " XML_FILE AUTH_CODES"
  exit 1
fi
# call awk script
awk -v authCodes="$(cat <)" -f filter-xml-trpcAuthCode.awk ""

我针对您的示例文件 main.xml and got four matching blocks. I was a little bit concerned about the output because in your sample output transaction_results.xml 测试了脚本(在 Windows 10 上的 cygwin 中使用 bash)只有三个匹配块。但是目视检查我的输出似乎是合适的。 (所有四个命中都包含一个匹配的 <trpcAuthCode> 元素。)

为了演示,我稍微减少了您的样本输入 sample.xml:

<?xml version="1.0"?>
<transSet periodID="1" periodname="Shift" longId="2017-04-27" shortId="052" site="12345">
  <trans type="periodClose">
    <trHeader>
    </trHeader>
  </trans>
  <printCashier>
    <cashier sysid="7" empNum="07" posNum="101" period="11">A.Dude</cashier>
  </printCashier>
  <trans type="printCashier">
    <trHeader>
      <cashier sysid="7" empNum="07" posNum="101" period="11">A.Dude</cashier>
      <posNum>101</posNum>
    </trHeader>
  </trans>
  <trans type="journal">
    <trHeader>
    </trHeader>
  </trans>
  <trans type="network sale" recalled="false">
    <trHeader>
      <termMsgSN type="FINANCIAL" term="908">31054</termMsgSN>
    </trHeader>
    <trPaylines>
      <trPayline type="sale" sysid="1" locale="DOLLAR">
        <trpCardInfo>
          <trpcAccount>1234567890123456</trpcAccount>
          <trpcAuthCode>532524</trpcAuthCode>
       </trpCardInfo>
      </trPayline>
    </trPaylines>
  </trans>
  <trans type="network sale" recalled="false">
    <trHeader>
      <termMsgSN type="FINANCIAL" term="908">31054</termMsgSN>
    </trHeader>
    <trPaylines>
      <trPayline type="sale" sysid="1" locale="DOLLAR">
        <trpPaycode mop="3" cat="1" nacstendercode="generic" nacstendersubcode="generic">CREDIT</trpPaycode>
        <trpAmt>61.77</trpAmt>
        <trpCardInfo>
          <trpcAccount>2345678901234567</trpcAccount>
          <trpcAuthCode>111222</trpcAuthCode>
        </trpCardInfo>
      </trPayline>
    </trPaylines>
  </trans>
  <trans type="periodClose">
    <trHeader>
      <date>2017-04-27T23:50:17-04:00</date>
    </trHeader>
  </trans>
  <endTotals>
    <insideSales>445938.63</insideSales>
  </endTotals>
</transSet>

对于其他示例输入,我只是将文本复制到一个文件中 authCodes.txt:

111222
111333
111444

在示例会话中使用两个输入文件:

$ ./filter-xml-trpcAuthCode.sh
ERROR: Illegal number of command line arguments!

Usage:
filter-xml-trpcAuthCode.sh XML_FILE AUTH_CODES

$ ./filter-xml-trpcAuthCode.sh sample.xml authCodes.txt
<!-- authCodeList:
111222
111333
111444
-->

  <trans type="network sale" recalled="false">
    <trHeader>
      <termMsgSN type="FINANCIAL" term="908">31054</termMsgSN>
    </trHeader>
    <trPaylines>
      <trPayline type="sale" sysid="1" locale="DOLLAR">
        <trpPaycode mop="3" cat="1" nacstendercode="generic" nacstendersubcode="generic">CREDIT</trpPaycode>
        <trpAmt>61.77</trpAmt>
        <trpCardInfo>
          <trpcAccount>2345678901234567</trpcAccount>
          <trpcAuthCode>111222</trpcAuthCode>
        </trpCardInfo>
      </trPayline>
    </trPaylines>
  </trans>

$ ./filter-xml-trpcAuthCode.sh main.xml authCodes.txt >output.txt

$

最后一个命令将输出重定向到一个文件 output.txt,之后可能会对其进行检查或处理。