Как выбрать несколько элементов с одинаковым именем с помощью xmlstarlet? - PullRequest
1 голос
/ 15 октября 2019

У меня есть следующий XML:

<a>
  <TICKET_LIST>
    <TICKET>
      <NUMBER>182820</NUMBER>
      <DETECTION>
        <IP network_id="173230">192.168.140.61</IP>
        <DNSNAME><![CDATA[local]]></DNSNAME>
        <PORT>80</PORT>
        <SERVICE>CGI</SERVICE>
        <PROTOCOL>tcp</PROTOCOL>
      </DETECTION>
      <VULNINFO>
        <TITLE><![CDATA[HTTP TRACE / TRACK Methods Enabled]]></TITLE>
        <TYPE>VULN</TYPE>
        <QID>12680</QID>
        <SEVERITY>3</SEVERITY>
        <STANDARD_SEVERITY>3</STANDARD_SEVERITY>
        <CVE_ID_LIST>
          <CVE_ID><![CDATA[CVE-2004-2320]]></CVE_ID>
          <CVE_ID><![CDATA[CVE-2010-0386]]></CVE_ID>
          <CVE_ID><![CDATA[CVE-2003-1567]]></CVE_ID>
        </CVE_ID_LIST>
      </VULNINFO>
    </TICKET>
    <TICKET>
      <NUMBER>182957</NUMBER>
      <DETECTION>
        <IP network_id="173230">192.168.200.46</IP>
        <DNSNAME><![CDATA[local]]></DNSNAME>
        <PORT>443</PORT>
        <SERVICE>Web server</SERVICE>
        <PROTOCOL>tcp</PROTOCOL>
      </DETECTION>
      <VULNINFO>
        <TITLE><![CDATA[Web Server Uses Plain-Text Form Based Authentication]]></TITLE>
        <TYPE>VULN</TYPE>
        <QID>86728</QID>
        <SEVERITY>3</SEVERITY>
        <STANDARD_SEVERITY>3</STANDARD_SEVERITY>
      </VULNINFO>
    </TICKET>
  </TICKET_LIST>
</a>

Я хотел бы экспортировать некоторые данные в формат CSV.

Этот код возвращает некоторые данные, как и ожидалось:

xmlstarlet  sel -T -t -m /a/TICKET_LIST/TICKET  -v "concat(NUMBER,',',DETECTION/IP,',',DETECTION/DNSNAME,',',DETECTION/SERVICE,',',DETECTION/PORT,',',VULNINFO/TITLE,',',VULNINFO/QID)" -n file.xml

Однако меня также интересуют все данные CVE_ID в той же строке, что и остальные данные.

Результат, который я получаю сейчас:

182820,192.168.140.61,local,CGI,80,HTTP TRACE / TRACK Methods Enabled,12680
182957,192.168.200.46,local,Web server,443,Web Server Uses Plain-Text Form Based Authentication,86728

Ожидаемые результаты:

182820,192.168.140.61,local,CGI,80,HTTP TRACE / TRACK Methods Enabled,12680,CVE-2004-2320 CVE-2010-0386 CVE-2003-1567
182957,192.168.200.46,local,Web server,443,Web Server Uses Plain-Text Form Based Authentication,86728

1 Ответ

0 голосов
/ 16 октября 2019

Поскольку имеется несколько CVE_ID элементов, вам необходимо добавить еще одно совпадение (-m), соответствующее VULNINFO/CVE_ID_LIST/CVE_ID.

Кроме того, для правильного вывода символа новой строки (-n) необходимо прервать вложение (-b).

Пример ...

xmlstarlet sel -T -t -m /a/TICKET_LIST/TICKET -v "concat(NUMBER,',',DETECTION/IP,',',DETECTION/DNSNAME,',',DETECTION/SERVICE,',',DETECTION/PORT,',',VULNINFO/TITLE,',',VULNINFO/QID,',')" -m VULNINFO/CVE_ID_LIST/CVE_ID -v "concat(.,' ')" -b -n file.xml

Вывод ...

182820,192.168.140.61,local,CGI,80,HTTP TRACE / TRACK Methods Enabled,12680,CVE-2004-2320 CVE-2010-0386 CVE-2003-1567
182957,192.168.200.46,local,Web server,443,Web Server Uses Plain-Text Form Based Authentication,86728,

Командная строка может иметь больше смысла, если вы видите XSLT, который xmlstarlet использует внутри (-C) ...

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
  <xsl:output omit-xml-declaration="yes" indent="no" method="text"/>
  <xsl:template match="/">
    <xsl:for-each select="/a/TICKET_LIST/TICKET">
      <xsl:call-template name="value-of-template">
        <xsl:with-param name="select" select="concat(NUMBER,',',DETECTION/IP,',',DETECTION/DNSNAME,',',DETECTION/SERVICE,',',DETECTION/PORT,',',VULNINFO/TITLE,',',VULNINFO/QID,',')"/>
      </xsl:call-template>
      <xsl:for-each select="VULNINFO/CVE_ID_LIST/CVE_ID">
        <xsl:call-template name="value-of-template">
          <xsl:with-param name="select" select="concat(.,' ')"/>
        </xsl:call-template>
      </xsl:for-each>
      <xsl:value-of select="'&#10;'"/>
    </xsl:for-each>
  </xsl:template>
  <xsl:template name="value-of-template">
    <xsl:param name="select"/>
    <xsl:value-of select="$select"/>
    <xsl:for-each select="exslt:node-set($select)[position()&gt;1]">
      <xsl:value-of select="'&#10;'"/>
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Обратите внимание, чтовторая строка вывода имеет трейлинг ,. Я не думаю, что это будет проблемой, так как все строки CSV будут иметь одинаковое количество столбцов.

Если это проблема, вы можете использовать "if" (-i) и проверить, есть ли какие-либо CVE_ID перед их обработкой ...

xmlstarlet sel -T -t -m /a/TICKET_LIST/TICKET -v "concat(NUMBER,',',DETECTION/IP,',',DETECTION/DNSNAME,',',DETECTION/SERVICE,',',DETECTION/PORT,',',VULNINFO/TITLE,',',VULNINFO/QID)" -i VULNINFO/CVE_ID_LIST/CVE_ID -o "," -m VULNINFO/CVE_ID_LIST/CVE_ID -v "concat(.,' ')" -b -n file.xml

Вывод такой же, как указано выше, за исключением того, что трейлинг , не выводится во второй строке ...

182820,192.168.140.61,local,CGI,80,HTTP TRACE / TRACK Methods Enabled,12680,CVE-2004-2320 CVE-2010-0386 CVE-2003-1567
182957,192.168.200.46,local,Web server,443,Web Server Uses Plain-Text Form Based Authentication,86728
...