XSL 1.0如何将XML嵌套节点值存入变量并正常调用
问题描述
我使用XSL 1.0,需要深层遍历XML节点序列提取值,以下是我的XML示例:
<?xml version="1.0" encoding="UTF-8"?> <mpcconfiguration> <lineitem id="0" seriesid="series1" modelid="model1"> <seriesdesc>Series #1</seriesdesc> <modeldesc>Model #1</modeldesc> <category id="Mstr_Information"> <option id="Mstr_Information"> <unitprice>0</unitprice> <property id="ExtPrice">0</property> <property id="Mstr_ModelSortOrder">3</property> </option> </category> </lineitem> <lineitem id="1" seriesid="series2" modelid="model2"> <seriesdesc>Series #2</seriesdesc> <modeldesc>Model #2</modeldesc> <category id="Mstr_Information"> <option id="Mstr_Information"> <description>descr1</description> <unitprice>0</unitprice> <property id="ExtPrice">0</property> <property id="Mstr_ModelSortOrder">1</property> </option> </category> </lineitem> <lineitem id="2" seriesid="series3" modelid="model3"> <seriesdesc>Series #3</seriesdesc> <modeldesc>Model #3</modeldesc> <category id="Mstr_Information"> <option id="Mstr_Information"> <description>descr1</description> <unitprice>0</unitprice> <property id="ExtPrice">0</property> <property id="Mstr_ModelSortOrder">2</property> </option> </category> </lineitem> </mpcconfiguration>
我要获取每个<lineitem>内目标值的选择器如下:
category[@id='Mstr_Information']/option[@id='Mstr_Information']/property[@id='Mstr_ModelSortOrder']
我已确认上述选择器正确,已在XSL顶部的排序逻辑中成功使用。我尝试按如下方式将该值提取到变量中:
<xsl:variable name="modelSortOrder"> <xsl:value-of select="category[@id='Mstr_Information']/option[@id='Mstr_Information']/property[@id='Mstr_ModelSortOrder']"/> </xsl:variable>
后续我按如下方式调用该变量:
<span style="width: 50px"> <b>Model Sort Order: </b> </span> <xsl:value-of select="$modelSortOrder" />
但运行失败,$modelSortOrder最终返回空字符串。以下是我当前精简后的可运行版本XSL:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ms="urn:schemas-microsoft-com:xslt"> <xsl:template match="mpcconfiguration"> <xsl:copy> <xsl:apply-templates select="@*" /> <xsl:apply-templates select="lineitem"> <xsl:sort select="category[@id='Mstr_Information']/option[@id='Mstr_Information']/property[@id='Mstr_ModelSortOrder']" data-type="number" /> </xsl:apply-templates> </xsl:copy> </xsl:template> <xsl:template match="lineitem"> <xsl:variable name="lineItemId"> <xsl:value-of select="@id"/> </xsl:variable> <xsl:variable name="seriesId"> <xsl:value-of select="@seriesid"/> </xsl:variable> <xsl:variable name="modelId"> <xsl:value-of select="@modelid"/> </xsl:variable> <xsl:variable name="modelSortOrder"> <xsl:value-of select="category[@id='Mstr_Information']/option[@id='Mstr_Information']/property[@id='Mstr_ModelSortOrder']"/> </xsl:variable> <div class="xRgn"> <table class="xInner"> <tr> <td class="col"> <xsl:element name="div"> <div style="float:left; margin:3px"> <span style="width: 50px"> <b>Series: </b> </span> <xsl:choose> <xsl:when test="not(seriesdesc)"> <xsl:value-of select="@seriesid" /> </xsl:when> <xsl:otherwise> <xsl:value-of select="seriesdesc" /> </xsl:otherwise> </xsl:choose> <br /> <span style="width: 50px"> <b>Model: </b> </span> <xsl:choose> <xsl:when test="not(modeldesc)"> <xsl:value-of select="@modelid" /> </xsl:when> <xsl:otherwise> <xsl:value-of select="modeldesc" /> </xsl:otherwise> </xsl:choose> <br /> <span style="width: 50px"> <b>Model Sort Order: </b> </span> <xsl:value-of select="$modelSortOrder" /> <br /> </div> </xsl:element> </td> </tr> </table> </div> </xsl:template> </xsl:stylesheet>
上述代码在我的.NET环境中运行基本正常(仅变量为空问题),排序逻辑、<lineitem>节点遍历、各节点对应的HTML生成结果均正确,寻求该变量空值问题的解决方法。
解决方案
该问题由XSLT 1.0的结果树片段(RTF)特性导致,.NET自带的XSLT处理器对这种写法兼容性较差:
你当前的变量定义方式是在变量标签内部嵌套<xsl:value-of>,这种写法会生成一个结果树片段,而非直接的字符串值,部分场景下读取时会返回空。
直接把变量的赋值方式改成用select属性即可解决:
<xsl:variable name="modelSortOrder" select="string(category[@id='Mstr_Information']/option[@id='Mstr_Information']/property[@id='Mstr_ModelSortOrder'])" />
这里加string()函数是为了显式把节点转为字符串值,进一步避免取值异常。
如果需要排查路径问题,可以临时在输出变量的位置加入调试代码,逐层验证节点是否存在:
<!-- 验证category节点是否存在 --> <xsl:value-of select="count(category[@id='Mstr_Information'])" /> <!-- 验证option节点是否存在 --> <xsl:value-of select="count(category[@id='Mstr_Information']/option[@id='Mstr_Information'])" /> <!-- 验证property节点是否存在 --> <xsl:value-of select="count(category[@id='Mstr_Information']/option[@id='Mstr_Information']/property[@id='Mstr_ModelSortOrder'])" />
你已经确认排序逻辑正常,说明路径完全正确,只需要修改变量定义方式即可。
内容的提问来源于stack exchange,提问作者HerrimanCoder
相关产品推荐
相关产品推荐

