使用来自唯一名称/ id的另一个元素的特定值添加属性到元素

时间:2014-07-12 17:25:55

标签: xml xslt xpath

我有一个xml文件,我尝试描述一些简单的用户界面,然后通过XSLT将其转换为带有XForms的有效html。我的意图是,这尽可能抽象,不应包含逻辑。但是使用XForms,您可以轻松地在多个控件之间进行绑定。我试图通过XSL转换来实现这个目标:

<structure>            
    <part class="TextInput" id="name"/>
    <part class="TextOutput" id="nameOutput"/>
</structure>
<style>
    <property part-name="name" name="label">Enter your name:</property>
    <property part-name="nameOutput" name="label">Output name:</property>
</style>
<behavior>
    <rule>
        <condition>
            <event part-name="name" class="binding"/>                 
        </condition>
        <action>
            <property part-name="name" bind="name"/>
        </action>
    </rule>
    <rule>
        <condition>
            <event part-name="nameOutput" class="binding"/>                 
        </condition>
        <action>
            <property part-name="nameOutput" bind="name"/>                        
        </action>
    </rule>
</behavior>

所以基本上,我这样描述 - 我有rule说明哪个part将绑定到其他part(所有部分都有唯一ids - 在这种情况下namenameOuput)。换句话说,在这个xml中我有2个部分,我想在每个部分中添加一个属性来定义可能的绑定。这是我无法弄清楚该怎么做......

这应该是有效输出:

<html
   xmlns="http://www.w3.org/1999/xhtml"
   xmlns:xf="http://www.w3.org/2002/xforms" 
   xmlns:xs="http://www.w3.org/2001/XMLSchema" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <head>
      <title>Test</title>
      <xf:model>
         <xf:instance xmlns="">
            <data>
               <name/>
            </data>
         </xf:instance>
         <xf:bind id="name" nodeset="/data/name"/>
      </xf:model>
   </head>
   <body>
       <xf:input id="name" ref="name" bind="name">
          <xf:label>Enter your name:</xf:label>
       </xf:input>
       <xf:output id="name" ref="name" bind="name">
          <xf:label>Output name:</xf:label>
       </xf:output>
   </body>
</html>

我现在到了这里:

.......
<body>
    <xf:input id="name" ref="name">
        <xf:label>Enter your name:</xf:label>
    </xf:input>
    <xf:output id="name" ref="name">
         <xf:label>Output name:</xf:label>
    </xf:output>
</body>
......

我实现了其他一切,除了我必须包含必须绑定到<xf:input><xf:output>元素作为属性(<xf:input bind="name">)的实例的部分。如您所见,缺少bind="part-name"属性。

我已将XSLT分发到不同的文件中以提高可读性/可维护性,但这里只负责转换为<xf:input> - 我想它应该足够了,但如果需要我可以分享其他文件。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xf="http://www.w3.org/2002/xforms" 
    exclude-result-prefixes="xs"
    version="2.0">    
    <xsl:key name="textLabels" match="property[@name='label']" use="@part-name"/>
    <xsl:template match="part[@class='TextInput'][key('textLabels', @id)]">
        <xf:input>
            <xsl:apply-templates select="@size | @style | @id"/>
            <!-- Create Reference to the XForms instance -->
            <xsl:attribute name="ref">
                <xsl:choose>
                    <xsl:when test="@id">
                        <xsl:value-of select="@id"/>
                    </xsl:when>
                    <xsl:when test="@name and not(@id)">
                        <xsl:value-of select="@name"/>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:value-of select="concat(local-name(.), position())"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:attribute>            
            <xsl:for-each select="behavior/rule/condition/event[@class='binding']">
                <xsl:attribute name="bind">
                    <xsl:value-of select="@part-name"/>
                </xsl:attribute>
            </xsl:for-each>
            <xf:label>
                <xsl:value-of select="key('textLabels', @id)"/>
            </xf:label>
        </xf:input>
    </xsl:template>    
</xsl:stylesheet>

那么如何在behavior / rule / action / property [@bind]中添加属性的值?在此先感谢:)

1 个答案:

答案 0 :(得分:1)

我认为问题在于这一行

 <xsl:for-each select="behavior/rule/condition/event[@class='binding']">

这导致两个问题。首先,它是一个相对的xpath表达式;相对于您所在的节点。在这种情况下,部分元素。但行为不是 part 的孩子,所以表达式不匹配!

其次,您正在查看所有规则元素,当我认为您只需要找到具有匹配部分名称的那个元素时。

要解决这个问题,您可以做的是首先定义一个键,通过绑定部件名称来查找规则元素

<xsl:key name="bindings" match="rule" use="condition/event[@class='binding']/@part-name"/>

然后,要在 xf:input 元素上创建 bind 属性,只需将现有的 xsl:for-each 替换为:

  <xsl:attribute name="bind">
      <xsl:value-of select="key('bindings', @id)/action/property/@bind"/>
  </xsl:attribute>
相关问题