XML return 所有节点名称都包含一个子字符串

XML return all node name contain a substring

由于我是 XPath/XQuery 的新手,并试图查询一个巨大的 xml 文件数据,所以我想,也许有人可以帮助我解决这个问题。

我有一个 xml 数据,如下所示:

<financial_statement>
  <revenue>123</revenue>
  <interestRevenue>234</interestRevenue>
  <salaries>12<salaries>
  <transactionRevenue>345</transactionRevenue>
  <revenueOtherServices>109</revenueOtherServices>
  <sales>783</sales>
  <costs>746</costs>
  .....
</financial_statement>

我想查询此 xml 数据和 return 仅查询名称中包含字符串 "revenue" 的节点。所以输出应该是这样的:

<revenue>
  <revenue>123</revenue>
  <interestRevenue>234</interestRevenue>
  <transactionRevenue>345</transactionRevenue>
  <revenueOtherServices>109</revenueOtherServices>
</revenue>

其实我并没有使用编程语言。我有一个 XML 数据库在 eXist 上本地运行,它包含一个内置的 XQuery 引擎。因此,我正在寻找 XPath/XQuery 代码。

提前致谢!

您可以使用name功能。这是一个 XSLT 1.0 解决方案。

<?xml version='1.0' encoding='UTF-8'?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="utf-8"/>

  <xsl:template match="*">
    <xsl:variable name="n" select="name (.)"/>
    <xsl:element name="{$n}">
      <xsl:for-each select="@*">
        <xsl:copy-of select="."/>
      </xsl:for-each>
      <xsl:apply-templates select="node()"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="text()">
    <xsl:value-of select="."/>
  </xsl:template>

  <xsl:template match="/">
    <xsl:element name="revenue">
      <xsl:apply-templates select="financial_statement"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="financial_statement">
    <xsl:for-each select="*">
      <xsl:variable name="n" select="name (.)"/>
      <xsl:if test="contains ($n, &quot;revenue&quot;) or contains ($n, &quot;Revenue&quot;)">
        <xsl:apply-templates select="."/>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

这为您的示例提供了所需的输出。

XQuery 解决方案可能如下所示。 Return 一个最外层的元素 revenue,并查找名称包含 "revenue" 的所有元素,无论是小写还是大写,这就是 translate() 函数所做的。

此处,输入文档被分配给变量 $x,但您也可以使用 doc() 函数或任何其他方式来检索 eXist 提供的 XML 数据。

XQuery

let $x := <financial_statement><revenue>123</revenue><interestRevenue>234</interestRevenue><salaries>12</salaries><transactionRevenue>345</transactionRevenue><revenueOtherServices>109</revenueOtherServices><sales>783</sales><costs>746</costs></financial_statement>

return <revenue>{$x//*[contains(translate(name(),'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'revenue')]}</revenue>

使用 translate() 保证可移植到 XPath 1.0,但由于 XQuery 使用 XPath 2.0,您还可以使用 lower-case()upper-case() 来模拟不区分大小写的 contains()功能。

XML输出

<revenue>
   <revenue>123</revenue>
   <interestRevenue>234</interestRevenue>
   <transactionRevenue>345</transactionRevenue>
   <revenueOtherServices>109</revenueOtherServices>
</revenue>

如果您真的需要 XSLT 解决方案,以下转换可以满足您的需求。由于 XQuery 和 XSLT 都使用 XPath,因此方法几乎相同。

XML 输入

<financial_statement>
  <revenue>123</revenue>
  <interestRevenue>234</interestRevenue>
  <salaries>12</salaries>
  <transactionRevenue>345</transactionRevenue>
  <revenueOtherServices>109</revenueOtherServices>
  <sales>783</sales>
  <costs>746</costs>
</financial_statement>

XSLT 样式表

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="xml" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />

    <xsl:template match="/">
      <revenue>
          <xsl:apply-templates/>
      </revenue>
    </xsl:template>

    <xsl:template match="*[contains(translate(name(),'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),'revenue')]">
        <xsl:copy-of select="."/>
    </xsl:template>

    <xsl:template match="text()"/>
</xsl:transform>

XML输出

<revenue>
   <revenue>123</revenue>
   <interestRevenue>234</interestRevenue>
   <transactionRevenue>345</transactionRevenue>
   <revenueOtherServices>109</revenueOtherServices>
</revenue>

Actually I am not using a programming language.

嗯,您知道,XQuery 一种编程语言。在我看来,就是。