我想从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>
答案 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输入都有一个根,因此/
始终匹配。但是:
xsl:param
用于绑定输入参数,而不是用于定义内部变量。query
元素,更不用说在文件的开头,因此select="/query"
语句会产生一个空集。scope
代码同样与输入XML中的任何内容无关。 您的第二个模板永远不会匹配,因为您的输入XML没有 document
元素。因此,此缺失的url
元素也没有document
属性。
通过最近的编辑扩展我们对输入XML的看法,您的第二个模板中的document
现在可以匹配。但是,您的第一个模板在/
(逻辑根)上匹配,从那里应用模板只会传递顶层的任何内容 - 在您的情况下,vce
元素。由于vce
没有匹配的模板,因此vce
个孩子都没有应用模板,并且由于document
是vce
的孙子,因此该模板永远不会匹配。
scope
和query
仍然无法找到,因此第一个模板的这些部分将继续失败。
答案 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>
但是对于不合格的处理器,它是一个纯粹的猜测可能有用的东西。