xpath - показывать указанную c строку (последнюю) текста многострочного узла - PullRequest
0 голосов
/ 23 апреля 2020

Можно ли показать только указанную c строку некоторого многострочного содержимого узла? Я анализирую некоторые junit. xml, и я хочу показать последнюю строку error узла. Так, например, для этих данных:

<testsuite>
<testcase>
<error message="test setup failure">some
lines 
of a lenghty
stacktrace
    s.shutdown(socket.SHUT_RDWR)
E   OSError: [Errno 107] Transport endpoint is not connected</error>
</testcase>
<testcase>
<error message="test setup failure">some
lines 
of a lenghty
stacktrace
    raise Exception(&quot;Connection closed by remote!&quot;)
E   Exception: Connection closed by remote!</error>
</testcase>
</testsuite>

Я хотел бы показать только

E   OSError: [Errno 107] Transport endpoint is not connected
E   Exception: Connection closed by remote!

Получение всего текста тривиально либо

/testsuite/testcase/error/text()
//error/text()

I попробовал ниже выражения xpath:

//error/text()[last()]

но они не работают. Я смог добиться того, чего хотел, используя xmlstarlet, вот так:

xmlstarlet sel -t -m "//error" -v "substring-after(., 'E   ')" -n

, но мне было интересно, можно ли достичь чего-то подобного с помощью чистого выражения XPath?

Ответы [ 2 ]

1 голос
/ 24 апреля 2020

Поскольку xmlstarlet поддерживает только XPath 1.0, но поддерживает функции расширения EXSLT, я бы порекомендовал использовать str: tokenize () для токенизации текста и возврата последнего токена.

Функции расширения EXSLT поддерживаются в XPath с помощью команды sel (-m и -v), но я не смог заставить ее работать. Я думаю, это из-за способа, которым xmlstarlet создает внутренний XSLT, который используется.

Я смог заставить его работать, используя команду "tr", хотя, создав свой собственный XSLT ...

XSLT 1.0 (test.xsl)

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:exslt="http://exslt.org/common" 
  xmlns:str="http://exslt.org/strings" version="1.0" extension-element-prefixes="exslt str">
  <xsl:output omit-xml-declaration="yes" indent="no"/>

  <xsl:template match="/">
    <xsl:for-each select="//error">
      <xsl:if test="not(position()=1)">
        <xsl:text>&#xA;</xsl:text>
      </xsl:if>
      <xsl:value-of select="str:tokenize(.,'&#xA;')[last()]"/>
    </xsl:for-each>  
  </xsl:template>

</xsl:stylesheet>

командная строка xmlstarlet

xmlstarlet tr test.xsl input.xml

Выход

E   OSError: [Errno 107] Transport endpoint is not connected
E   Exception: Connection closed by remote!

Если вы используете что-то, поддерживающее XSLT 2.0, вы можете сделать что-то вроде этого:

for $err in //error return tokenize($err, '&#xA;')[last()]

Примечание. Возможно, вам придется изменить &#xA; на \n в некоторые из онлайн-тестеров XPath.

1 голос
/ 23 апреля 2020

Попробуйте использовать выражение xpath, например

//testcase//error/substring-after(.,"E ")

Выходные данные должны быть:

OSError: [Errno 107] Transport endpoint is not connected
Exception: Connection closed by remote!
...