xml 如果在 xsl 中使用 xsl 变量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4032400/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use xsl variable in xsl if
提问by Jason
I am trying to assign a value from an xsl variable to a new node in my xml file. This code works, but adds an empty PROP/PVAL node when the value of "lbi:GetCoordinates(PVAL)" is empty:
我正在尝试将 xsl 变量中的值分配给我的 xml 文件中的新节点。此代码有效,但当 "lbi:GetCoordinates(PVAL)" 的值为空时,会添加一个空的 PROP/PVAL 节点:
<xsl:template match="PROP" mode="Geocode">
<PROP NAME="Geocode">
<PVAL>
<xsl:value-of select="lbi:GetCoordinates(PVAL)"/>
</PVAL>
</PROP>
</xsl:template>
As I don't want any empty nodes, I am trying to only add the new node only when the value of "lbi:GetCoordinates(PVAL)" is not empty. The approach I am trying is to assign the value to a variable and test that variable, as below. Unfortunately, when I do this I get no new PROP nodes, even when lbi:GetCoordinates(PVAL) returns a non-empty value.
由于我不想要任何空节点,因此我仅在“lbi:GetCoordinates(PVAL)”的值不为空时才尝试仅添加新节点。我正在尝试的方法是将值分配给一个变量并测试该变量,如下所示。不幸的是,当我这样做时,我没有得到新的 PROP 节点,即使 lbi:GetCoordinates(PVAL) 返回一个非空值。
<xsl:template match="PROP" mode="Geocode">
<xsl:variable name="coords" select="'lbi:GetCoordinates(PVAL)'"/>
<xsl:if test="not(string-length(coords) = 0)">
<PROP NAME="Geocode">
<PVAL>
<xsl:value-of select="coords"/>
</PVAL>
</PROP>
</xsl:if>
</xsl:template>
Can anyone point me in the right direction, or suggest a better way of achieving this?
谁能指出我正确的方向,或提出更好的方法来实现这一目标?
The source xml is like this:
源xml是这样的:
<RECORD>
<PROP name="PostCode">
<PVAL>N11 1NN</PVAL>
</PROP>
</RECORD>
and the template is referenced thus:
并且模板是这样引用的:
<xsl:template match="RECORD">
<xsl:copy>
<xsl:apply-templates select="PROP[@NAME='PostCode']" mode="Geocode"/>
</xsl:copy>
The lbi:GetCoordinates() method is in an external .Net assembly added as an xml namespace.
lbi:GetCoordinates() 方法位于作为 xml 命名空间添加的外部 .Net 程序集中。
Using this approach works:
使用这种方法有效:
<xsl:template match="PROP[string-length(lbi:GetCoordinates(PVAL))>0]" mode="Geocode">
<PROP NAME="Geocode">
<PVAL>
<xsl:value-of select="lbi:GetCoordinates(PVAL)"/>
</PVAL>
</PROP>
The problem now is that the lbi:GetCoordinates method is called twice when it only needs to be called once, the source xml can have 100,000+ elements that need geocoding so this is non-trivial. This suggests to me that the xsl:variable expression I used earlier is incorrect and the variable always ends up as empty.
现在的问题是 lbi:GetCoordinates 方法在只需要调用一次时会被调用两次,源 xml 可以有 100,000 多个需要地理编码的元素,所以这很重要。这向我表明我之前使用的 xsl:variable 表达式是不正确的,并且该变量总是以空结尾。
采纳答案by Dimitre Novatchev
<xsl:variable name="coords" select="'lbi:GetCoordinates(PVAL)'"/>
<xsl:if test="not(string-length(coords) = 0)">
This is "almost" correct. The only problem is the quotes around lbi:GetCoordinates(PVAL). These convert the return value from an extension function-- just to the string of the expression that invokes this function. As the length of this string is obviously greater than 0, the test on the second line will allways be true.
这是“几乎”正确的。唯一的问题是周围的引号lbi:GetCoordinates(PVAL)。这些将来自扩展函数的返回值转换为调用该函数的表达式的字符串。由于该字符串的长度明显大于0,因此第二行的测试将始终为真。
From here on I suppose that the lbi:GetCoordinates()function returns a string or an atomic value (not a node or a node-set), because you haven't said anything about the return type of the function, but this is very important!
从这里开始,我假设该lbi:GetCoordinates()函数返回一个字符串或一个原子值(不是一个节点或一个节点集),因为您还没有说明函数的返回类型,但这非常重要!
You want(note that the quotes are missing now!):
您想要(请注意现在缺少引号!):
<xsl:variable name="coords" select="lbi:GetCoordinates(PVAL)"/>
<xsl:if test="not(string-length(coords) = 0)">
**But even this is a little bit clumsy.
**但即使这样也有点笨拙。
Solution: Use the power of XSLT template match patterns and avoid the conditional logic inside the template altogether:
解决方案:利用 XSLT 模板匹配模式的强大功能,完全避免模板内部的条件逻辑:
<xsl:template match="PROP[string-length(lbi:GetCoordinates(PVAL))]"
mode="Geocode">
<PROP NAME="Geocode">
<PVAL>
<xsl:value-of select="lbi:GetCoordinates(PVAL)"/>
</PVAL>
</PROP>
</xsl:template>
Don't worry that the lbi:GetCoordinates(PVAL)function is called twice because a good optimizing XSLT processor will only call it once. You may always conduct some tests and see if this is the case.
不要担心lbi:GetCoordinates(PVAL)函数被调用两次,因为一个好的优化 XSLT 处理器只会调用它一次。您可能总是进行一些测试,看看是否是这种情况。
In the worst case, if the XSLT processor is dumb and calls the function twice, then use the clumsier code above.
在最坏的情况下,如果 XSLT 处理器是愚蠢的并且调用该函数两次,则使用上面的笨拙代码。
回答by Andrew Bezzub
Try to use string-length(coords) > 0instead of your condition .
尝试使用string-length(coords) > 0代替您的条件。
回答by alfirin
if your source-xml looks somewhat like this:
如果你的 source-xml 看起来有点像这样:
<PROP>
<lbi:GetCoordinates(PVAL)>sometext</lbi:Getcoordinates(PVAL>
</PROP>
this should do the trick:
这应该可以解决问题:
<xsl:template match="PROP[string-length(lbi:GetCoordinates(PVAL))>0]" mode="Geocode">
<PROP NAME="Geocode">
<PVAL>
<xsl:value-of select="lbi:GetCoordinates(PVAL)"/>
</PVAL>
</PROP>
</xsl:template>
I changed the match-clause to filter early, you could also just try to change your if-statement from not(string-length()=0)to string-length>0
我将匹配子句更改为提前过滤,您也可以尝试将 if 语句从 更改not(string-length()=0)为string-length>0
I don't have an environment to test it out at the moment, consider including your source-xml, as it is vital to how exactly the xslt should be constructed
我目前没有测试它的环境,请考虑包含您的 source-xml,因为这对于应该如何构建 xslt 至关重要

