【问题标题】:How to match identifiers ?如何匹配标识符?
【发布时间】:2016-05-22 14:15:25
【问题描述】:

我在从 XML 到 HTML 的 XSL 转换中匹配不同的标识符时遇到问题。我有一长串链接元素,如下所示:

<link target="#E_1 #FCB_1 #FWH_2 #FWH_3">

target 属性中以 # 开头的每个文本都匹配段落元素中的 xml:id 属性,如下所示:

<p xml:id="E_1">text text text</p>
<p xml:id="FCB_1">text text text</p>
<p xml:id="FWH_2">text text text</p>
<p xml:id="FWH_3">text text text</p>

我需要做的是为每个目标属性创建一个div元素,意思是获取以下内容:

<div class="impair">
<div>
<p>Content of the paragraph with xml:id equal to "E_1"</p>
</div>
<div>
<p>Content of the paragraph with xml:id equal to "FCB_1"</p>
</div>
<div>
<p>Content of the paragraph with xml:id equal to "FWH_2"</p>
</div>
<div>
<p>Content of the paragraph with xml:id equal to "FWH_3"</p>
</div>
</div>

我已经尝试过使用 xsl:variable、xsl:param、xsl:key 或诸如starts-with 甚至子字符串之类的函数,但目前没有任何效果。所以我在寻求帮助。我仍在努力提高我的 XSL 技能... 非常感谢您的帮助。 弗洛尔

【问题讨论】:

  • 您是否使用像 Saxon 9 这样的 XSLT 2.0 处理器?

标签: xml xslt


【解决方案1】:

假设使用 XSLT 2.0 处理器,您可以将 id 函数与来自 target 属性的标记化值一起使用:

<xsl:template match="link[@target]">
    <div class="impair">
        <xsl:apply-templates select="id(for $idref in tokenize(@target, '\s+') return substring($idref, 2))" mode="wrap"/>
    </div>
</xsl:template>

<xsl:template match="p" mode="wrap">
    <div>
        <xsl:copy>
            <xsl:apply-templates/>
        </xsl:copy>
    </div>
</xsl:template>

【讨论】:

    【解决方案2】:

    如果您正在寻找 XSLT 1.0 解决方案,这里有一种可能的方法,它将 target 属性转换为字符串 #E_1#FCB_1#FWH_2#FWH_3# 并使用各种字符串函数来选择 p 元素,其 id 出现在那个字符串。

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
      <xsl:template match="/">
          <xsl:apply-templates select="//link" />
      </xsl:template>
    
      <xsl:template match="link">
        <xsl:variable name="target" select="concat(translate(@target, ' ', ''), '#')" />
        <xsl:value-of select="$target" />
        <div class="impair">
          <xsl:apply-templates select="//p[contains($target, concat('#', @xml:id, '#'))]">
            <xsl:sort select="string-length(substring-before($target, concat('#', @xml:id, '#')))" />
          </xsl:apply-templates>
        </div>
      </xsl:template>
    
      <xsl:template match="p">
        <div>
          <p><xsl:value-of select="." /></p>
        </div>
      </xsl:template>
    </xsl:stylesheet>
    

    如果您在 target 属性中重复了 ID,这将不起作用,例如 #E_1 #FCB_1 #FWH_3 #FWH_3。在这种情况下,递归调用命名模板可以拆分target 属性:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
      <xsl:key name="p" match="p" use="concat('#', @xml:id)" />
    
      <xsl:template match="/">
          <xsl:apply-templates select="//link" />
      </xsl:template>
    
      <xsl:template match="link">
        <div class="impair">
            <xsl:call-template name="split">
              <xsl:with-param name="string" select="@target" />
            </xsl:call-template>
        </div>
      </xsl:template>
    
      <xsl:template name="split">
        <xsl:param name="string" />
        <xsl:if test="$string != ''">
          <xsl:apply-templates select="key('p', substring-before(concat($string, ' '), ' '))" />
          <xsl:if test="contains($string, ' ')">
            <xsl:call-template name="split">
              <xsl:with-param name="string" select="substring-after($string, ' ')" />
            </xsl:call-template>
          </xsl:if>
        </xsl:if>
      </xsl:template>
    
      <xsl:template match="p">
        <div>
          <p><xsl:value-of select="." /></p>
        </div>
      </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

      猜你喜欢
      • 2022-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多