【问题标题】:XML return all node name contain a substringXML 返回所有节点名包含一个子字符串
【发布时间】:2015-04-12 05:30:38
【问题描述】:

由于我是 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 数据并仅返回名称中包含字符串“revenue”的节点。所以输出应该是这样的:

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

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

提前致谢!

【问题讨论】:

    标签: xml xpath xquery


    【解决方案1】:

    XQuery 解决方案可能如下所示。返回最外层元素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>
    

    实际上我没有使用编程语言。

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

    【讨论】:

    • 其实我只是问了XQuery,我只需要搜索一个巨大的XML fkes 的集合。非常感谢。我刚试了一下,效果很好 :) Vielen Dank ;)
    【解决方案2】:

    您可以使用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>
    

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

    【讨论】:

    • 我认为 OP 没有要求 XSLT 解决方案。此外,您不需要 任何 的 for-each 语句或变量。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-25
    • 2014-05-25
    • 2011-06-15
    • 2016-11-20
    相关资源
    最近更新 更多