XSLT:将全局变量设置为属性值

时间:2017-05-24 13:56:40

标签: xslt xslt-1.0

常规 我正在尝试修改包含JavaScript的XML。如果JavaScript引用其中一个页面顶级,我想添加一个额外的顶级层次结构级别。

具体细节 我想找到新的顶级(formName),然后将它们添加到脚本中,如果它们具有以页面顶层(pageNames和subPageNames)开头的分配。我试图在XMLSpy中运行它,但我甚至无法填充变量formName。解决这个问题的最佳方法是什么?

我的示例XML:

<?xml version="1.0" encoding="UTF-8"?>
<template>
  <subform name="formABC">
    <pageSet>
        <pageArea name="Page1">
            <subform>
                <field>
                    <event>
                        <script>this.rawValue = SubPageA.subhuvud.namn.rawValue;</script>
                    </event>
                </field>
                <field>
                    <event>
                        <script>this.rawValue = not_this.rawValue;</script>
                    </event>
                </field>
            </subform>
        </pageArea>
        <pageArea name="Page2">
            <field>
                <event>
                    <script>this.rawValue = SubPageK.subhuvud.namn.rawValue;</script>
                </event>
            </field>
            <area>
                <field>
                    <event>
                        <script>this.rawValue = Page1.subhuvud.namn.rawValue;</script>
                    </event>
                </field>
                <field>
                    <event>
                        <script>this.rawValue = other.rawValue;</script>
                    </event>
                </field>
            </area>
        </pageArea>
    </pageSet>
    <subform name="SubPageA">
    </subform>
    <subform name="SubPageK">
    </subform>
  </subform>
</template>

我目前的XSL:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common" extension-element-prefixes="exsl"
xmlns:xdp="http://ns.adobe.com/xdp/">
<xsl:output omit-xml-declaration="yes" indent="yes"/>

<xsl:variable name="formName"     select="/xdp:xdp/template/subform/@name"/>
<xsl:variable name="pageNames"    select="/xdp:xdp/template/subform/subform/@name"/>
<xsl:variable name="subPageNames" select="/xdp:xdp/template/subform/pageSet/pageArea/@name"/>
<xsl:variable name="allPageNames" select="concat($pageNames, $subPageNames)"/>

<!--    Identity rule.-->
<xsl:template match="node()|@*">
    <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
</xsl:template>

<!--Rewite Javascript-->
<!--Insert formname in front of page that is first.-->
<xsl:template match="//script">
    <xsl:variable name="match" select="exsl:node-set($allPageNames)[contains(current(), .)]"/>
    <xsl:choose>
        <xsl:when test="$match">                                                <!--this.rawValue = Page1.subhuvud.namn.rawValue;-->
            <xsl:value-of select="substring-before(., $match)"/>                <!--this.rawValue = -->
            <xsl:value-of select="$formName"/>                                  <!--formABC-->
            <xsl:value-of select="'.'"/>                                        <!--.-->
            <xsl:value-of select="$match"/>                                     <!--Page1-->
            <xsl:value-of select="substring-after(., $match)"/>                 <!--.subhuvud.namn.rawValue;-->
        </xsl:when>                                                             <!--this.rawValue = formABC.Page1.subhuvud.namn.rawValue;-->
        <xsl:otherwise>
            <xsl:copy/>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>
</xsl:stylesheet>

我寻求的输出:

<?xml version="1.0" encoding="UTF-8"?>
<template>
 <subform name="formABC">
    <pageSet>
        <pageArea name="Page1">
            <subform>
                <field>
                    <event>
                        <script>this.rawValue = formABC.SubPageA.subhuvud.namn.rawValue;</script>
                    </event>
                </field>
                <field>
                    <event>
                        <script>this.rawValue = not_this.rawValue;</script>
                    </event>
                </field>
            </subform>
        </pageArea>
        <pageArea name="Page2">
            <field>
                <event>
                    <script>this.rawValue = formABC.SubPageK.subhuvud.namn.rawValue;</script>
                </event>
            </field>
            <area>
                <field>
                    <event>
                        <script>this.rawValue = formABC.Page1.subhuvud.namn.rawValue;</script>
                    </event>
                </field>
                <field>
                    <event>
                        <script>this.rawValue = other.rawValue;</script>
                    </event>
                </field>
            </area>
        </pageArea>
    </pageSet>
    <subform name="SubPageA">
    </subform>
    <subform name="SubPageK">
    </subform>
  </subform>
  </template>

1 个答案:

答案 0 :(得分:1)

关于绑定变量的值,我扩展了我的注释,指出以select为根的/xdp:xdp表达式永远不会匹配示例输入文件中的任何内容,因此关联变量的值将永远是空节点集。您应该能够通过删除该元素来解决该问题(关于示例输入):

<xsl:variable name="formName" select="/template/subform/@name"/>

接下来,我发现你为变量allPageNames形成值的机制不起作用,因为concat()需要 string 参数,但是你试图提供节点集。也不会将节点集转换为字符串做正确的事情,因为

  1. 将节点集转换为字符串可获取第一个节点的字符串值(仅限)
  2. 您正试图形成一个无限制的连接,之后您将无法从中提取原始字符串。
  3. 在实际使用该值的地方,您将其转换为节点集,那么首先将值生成为节点集是不是更好?
  4. XPath有一个节点集联合运算符|,您可以在表达式中使用此变量的值。例如,

    <xsl:variable name="pageNames"    select="/template/subform/subform/@name"/>
    <xsl:variable name="subPageNames" select="/template/subform/pageSet/pageArea/@name"/>
    <xsl:variable name="allPageNames" select="$pageNames | $subPageNames"/>
    

    现在你不需要EXSL(针对你在问题中提出的内容),因为allPageNames已经是一个节点集。

    但这还不够:match模板中的变量script存在问题。其赋值中的select表达式将不起作用,因为contains()是另一个字符串函数,并且您正在尝试将节点集传递给它。此外,在谓词内部,它将评估正在测试的节点 not ,因为它看起来你想要,正在转换<script>元素。在任何情况下,您似乎试图执行的测试都容易出现误报。

    我建议采用不同的方法。首先,确定要测试的对象的名称。当使用script元素作为上下文节点进行处理时,这看起来可能与您描述的目标一致:

    <xsl:variable name="topObject"
        select="normalize-space(substring-before(concat(substring-after(., '='), '.'), '.'))"/>
    

    完成此操作后,您可以测试所选名称是否属于$allPageNames节点通过此测试表达式设置的名称:$allPageNames[. = $topObject]。总的来说,script模板可能如下所示:

    <xsl:template match="script">
      <!-- assumed: this element has text-only content -->
      <xsl:variable name="topObject"
          select="normalize-space(substring-before(concat(substring-after(., '='), '.'), '.'))"/>
      <xsl:copy>
        <xsl:apply-templates select="@*"/>
        <xsl:choose>
          <xsl:when test="$allPageNames[. = $topObject]">
            <xsl:value-of select="substring-before(., $topObject)"/>
            <xsl:value-of select="$formName"/>
            <xsl:text>.</xsl:text>
            <xsl:value-of select="$topObject"/>
            <xsl:value-of select="substring-after(., $topObject)"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:apply-templates select="text()"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:copy>
    </xsl:template>