XSL商店价值

时间:2017-04-12 00:23:01

标签: xml xslt xslt-1.0

我想从XML输入中存储变量。然后我将使用此值来测试另一个元素值。 XML由IBM Watson Explorer生成。 这是XML(更新):

<vce>
  <param name="v:project" value="pru-collection"/>
  <param name="query" value="xyz"/>
  <param name="render.function" value="xml-feed-display"/>
  <param name="content-type" value="text/xml"/>
  <list path="" num="23" level="0" start="0" per="25">
    <document url="https://example.net">
      <content name="Avatar_Image" type="text">...</content>
      <content name="keywords" type="text">xyz</content>
      <content name="owner" type="text">...</content>
    </document>
    <document url="https://example.net">
      <content name="Avatar_Image" type="text">...</content>
      <content name="keywords" type="text">123</content>
      <content name="owner" type="text">...</content>
    </document>
    <document url="https://example.net">
      <content name="Avatar_Image" type="text">...</content>
      <content name="keywords" type="text">abc</content>
      <content name="owner" type="text">...</content>
    </document>
  </list>
</vce>

这是我的XSL。这是IBM应用程序内部的自由文本XSL样式表:

    <xsl:template match="/">
        <xsl:param name="saveQuery" select="**../param[@name='query']/@value**" />
        <scope>
            <xsl:copy-of select="/scope/*[not(name() = 'document')]" />
            <boost name="df" />
            <xsl:apply-templates />
        </scope>
    </xsl:template>

    <xsl:template match="document">
        <document url="{@url}">
            <xsl:if test="viv:test(content[@name='keywords'], '$saveQuery', 'case-insensitive-regex')">
               <xsl:attribute name="boost-name">df</xsl:attribute>
               <xsl:attribute name="boost-display">boost-and-list</xsl:attribute>
            </xsl:if>
         <xsl:copy-of select="@*" />
         <xsl:copy-of select="* | text() | comment()" />
        </document>
    </xsl:template>

看起来$saveQuery未正确存储'query'标记的值。出于测试目的,通过手动比较content[@name='keywords'与实际值xyz而不是$saveQuery,它可以正常工作。

更新代码

<xsl:template match="/vce">
<scope>
  <xsl:copy-of select="/scope/*[not(name() = 'document')]" />
  <boost name="df" />
  <xsl:apply-templates />
  <xsl:apply-templates>
    <xsl:with-param name="saveQuery" select="param[@name='query']/@value" />
  </xsl:apply-templates>
</scope>
</xsl:template>
<xsl:template match="*">
  <xsl:param name="saveQuery" />
  <xsl:apply-templates>
     <xsl:with-param name="saveQuery" select="$saveQuery" />
  </xsl:apply-templates>
</xsl:template>
<xsl:template match="document">
  <xsl:param name="saveQuery" />
  <document url="{@url}">
    <xsl:if test="viv:test(content[@name='keywords'], '$saveQuery', 'case-insensitive-regex')">
      <xsl:attribute name="boost-name">df</xsl:attribute>
      <xsl:attribute name="boost-display">boost-and-list</xsl:attribute>
    </xsl:if>
    <xsl:copy-of select="@*" />
    <xsl:copy-of select="* | text() | comment()" />
  </document>
</xsl:template>

更新了2.0 此代码在xsltransform工具中工作正常,但在IBM环境中不工作。任何想法人们为什么仍然没有将值传递给saveQuery?或者可能有关于不同方法的想法?

<xsl:template match="/vce">
  <scope>
    <xsl:apply-templates select="list/document">
    <xsl:with-param name="saveQuery" select="'xyz'" />
    </xsl:apply-templates>
  </scope>
</xsl:template>

<xsl:template match="document">
  <!-- for chk this line works -->
  <!-- <xsl:param name="saveQuery" select="'xyz'"/>-->
   <xsl:param name="saveQuery" />
   <document>
      <xsl:if test="content[@name='keywords'] = $saveQuery">
         <xsl:attribute name="boost-name">df</xsl:attribute>
         <xsl:attribute name="boost-display">boost-and-list</xsl:attribute>
      </xsl:if>
      <xsl:copy-of select="@*" />
      <xsl:copy-of select="* | text() | comment()" />
   </document>
</xsl:template>

3 个答案:

答案 0 :(得分:1)

要执行此类操作,您需要将参数从一个模板传递到另一个模板。在调用模板中:

<xsl:apply-templates select="document">
  <xsl:with-param name="saveQuery" select="./query"/>
</xsl:apply-templates>

在被叫模板中:

<xsl:template match="document">
  <xsl:param name="query"/>
  ...
</xsl:template>

XSLT中的变量具有静态范围 - 当您使用$var引用变量或参数时,变量var必须在全局声明中声明,或者更早在相同的模板或功能中。

答案 1 :(得分:0)

您的第一个模板匹配,因为任何格式良好的XML输入都有一个根,因此/始终匹配。但是:

  1. 在最佳实践中,xsl:param用于绑定输入参数,而不是用于定义内部变量。
  2. 输入XML中的任何位置都没有query元素,更不用说在文件的开头,因此select="/query"语句会产生一个空集。
  3. 您的scope代码同样与输入XML中的任何内容无关。
  4. 您的第二个模板永远不会匹配,因为您的输入XML没有document元素。因此,此缺失的url元素也没有document属性。

    更新

    通过最近的编辑扩展我们对输入XML的看法,您的第二个模板中的document现在可以匹配。但是,您的第一个模板在/(逻辑根)上匹配,从那里应用模板只会传递顶层的任何内容 - 在您的情况下,vce元素。由于vce没有匹配的模板,因此vce个孩子都没有应用模板,并且由于documentvce的孙子,因此该模板永远不会匹配。

    scopequery仍然无法找到,因此第一个模板的这些部分将继续失败。

答案 2 :(得分:0)

我猜你想做点什么:

<xsl:template match="/vce">
    <scope>
        <!-- some content here -->
        <xsl:apply-templates select="list/document">
            <xsl:with-param name="saveQuery" select="param[@name='query']/@value"/>
        </xsl:apply-templates>
    </scope>
</xsl:template>

<xsl:template match="document">
    <xsl:param name="saveQuery"/>
    <document>
        <!-- use the parameter here -->
    </document>
</xsl:template>

请注意xsl:apply-templates显式选择目标document元素,因此参数值将直接传递给匹配模板。如果没有这个,您将不得不添加自己的模板来替换确保递归的内置模板,并使其在遍历树时携带参数:

<xsl:template match="/vce">
    <scope>
        <!-- some content here -->
        <xsl:apply-templates>
            <xsl:with-param name="saveQuery" select="param[@name='query']/@value"/>
        </xsl:apply-templates>
    </scope>
</xsl:template>

<xsl:template match="*">
    <xsl:param name="saveQuery"/>
    <xsl:apply-templates>
        <xsl:with-param name="saveQuery" select="$saveQuery"/>
    </xsl:apply-templates>
</xsl:template>

<xsl:template match="document">
    <xsl:param name="saveQuery"/>
    <document>
        <!-- use the parameter here -->
    </document>
</xsl:template>

加了:

显然您的处理器不合规。您可以尝试直接从目标模板访问节点,例如类似的东西:

<xsl:template match="/vce">
    <scope>
        <!-- some content here -->
        <xsl:apply-templates select="list/document"/>
    </scope>
</xsl:template>

<xsl:template match="document">
    <xsl:variable name="saveQuery" select="/vce/param[@name='query']/@value"/>
    <document>
        <!-- use the variable here -->
    </document>
</xsl:template>

甚至更直接地:

<xsl:template match="document">
    <document>
        <xsl:if test="content[@name='keywords']=/vce/param[@name='query']/@value">
            <xsl:attribute name="boost-name">df</xsl:attribute>
            <xsl:attribute name="boost-display">boost-and-list</xsl:attribute>
        </xsl:if>
        <xsl:copy-of select="@*|node()" />
    </document>
</xsl:template>

但是对于不合格的处理器,它是一个纯粹的猜测可能有用的东西。