如何使用fn:替换所选属性?

时间:2014-07-14 13:11:20

标签: xml regex xslt xpath

我没有使用xslt的经验,但我正在尝试通过调整一些代码来学习。

在XML中,我有多次出现不同的idrid,如下所示:

<fn id="TFN01t1"><label>*</label><p>Some text.</p></fn>
<fn id="TFN02t1"><label>**</label><p>Some text.</p></fn>
...
<p>This is a reference<xref ref-type="table-fn" rid="TFN01t1">*</xref></p>
<p>This is another reference<xref ref-type="table-fn" rid="TFN02t1">*</xref></p>

我需要在fn标签的ID属性中执行以下正则表达式,在任何外部参照标记的RID属性中执行 ,并交换数字部分,以便TFN02t1变为TFN1t02。

        "find": TFN([0-9]+)t([1-9]+)
        "replace": TFN\2t\1

我找到this SO answer about fn:replace但不知道如何使用它。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

如果你可以不使用正则表达式,你也可以使用这个简单的XSLT1兼容解决方案:

输入

<root>
  <fn id="TFN01t1"><label>*</label><p>Some text.</p></fn>
  <fn id="TFN02t1"><label>**</label><p>Some text.</p></fn>
  <p>This is a reference<xref ref-type="table-fn" rid="TFN01t1">*</xref></p>
  <p>This is another reference<xref ref-type="table-fn" rid="TFN02t1">*</xref></p>
</root>

样式表

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="utf-8"/>

  <xsl:template match="fn/@id | xref[@ref-type = 'table']/@rid">
    <xsl:variable name="after-tfn" select="substring-after(., 'TFN')"/>
    <xsl:variable name="n1" select="substring-before($after-tfn, 't')"/>
    <xsl:variable name="n2" select="substring-after($after-tfn, 't')"/>

    <xsl:attribute name="{local-name()}">
      <xsl:value-of select="concat('TFN', $n2, 't', $n1)"/>
    </xsl:attribute>
  </xsl:template>

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

输出

<?xml version="1.0" encoding="utf-8"?>
<root>
  <fn id="TFN1t01"><label>*</label><p>Some text.</p></fn>
  <fn id="TFN1t02"><label>**</label><p>Some text.</p></fn>
  <p>This is a reference<xref ref-type="table-fn" rid="TFN1t01">*</xref></p>
  <p>This is another reference<xref ref-type="table-fn" rid="TFN1t02">*</xref></p>
</root>

如果你可以使用XSLT2并想使用正则表达式,这个样式表应该会得到相同的结果:

样式表

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="utf-8"/>

  <xsl:template match="fn/@id | xref/@rid">
    <xsl:attribute name="{local-name(.)}">
      <xsl:analyze-string select="." regex="TFN([0-9]+)t([1-9]+)">
        <xsl:matching-substring>
          <xsl:value-of select="concat('TFN', regex-group(2), 't', regex-group(1))"/>
        </xsl:matching-substring>
      </xsl:analyze-string>
    </xsl:attribute>
  </xsl:template>

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

有关XSLT2中正则表达式支持的更多信息,请参阅Regular Expression Matching in XSLT 2

答案 1 :(得分:2)

如果您尝试通过调整现有代码来尝试这样做,那么在没有能够看到现有代码的情况下帮助您有点困难。

您需要一个与相关节点匹配的模板规则,例如

<xsl:template match="fn/@id | xref/@rid">
  <xsl:attribute name="{name()}" select="replace('.', 'TFN([0-9]+)t([1-9]+)',
        'TFN$2t$1')"/>
</xsl:template>

然后你需要确保样式表中的某个地方对xsl:apply-templates进行调用,选择这些属性节点进行处理,因为如果没有这个,你的模板规则永远不会被调用。