XSLT字符串替换为函数

时间:2017-02-06 10:23:49

标签: xml xslt xslt-1.0

我有这个mods

<?xml version="1.0" encoding="UTF-8"?>
<modsCollection xmlns="http://www.loc.gov/mods/v3" xmlns:dabar="http://dabar.srce.hr/standards/schema/1.0" xmlns:mads="http://www.loc.gov/mads/v2" xmlns:mods="http://www.loc.gov/mods/v3" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink">
  <mods ID="master">
    <relatedItem type="constituent">
      <identifier>777777</identifier>
      <titleInfo type="alternative">
        <title>EXTRA</title>
      </titleInfo>
      <titleInfo lang="hrv">
        <title>PRE/POST</title>
      </titleInfo>
      <identifier type="local">666666</identifier>
      <name type="corporate" displayLabel="jurisdiction" authority="iso3166">
        <namePart>EU</namePart>
      </name>
      <name type="corporate">
        <namePart>EC</namePart>
      </name>
      <name>
        <namePart>H200</namePart>
      </name>
      <name type="personal">
        <role>
          <roleTerm type="text" authority="marcrelator">Project director</roleTerm>
          <roleTerm lang="hrv">Voditelj projekta</roleTerm>
        </role>
        <namePart>Name Surname</namePart>
      </name>
    </relatedItem>
   </mods>
</modsCollection>

我有这种转变

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xmlns:mods="http://www.loc.gov/mods/v3" exclude-result-prefixes="mods"
                xmlns:mads="http://www.loc.gov/mads/v2"
                xmlns:dabar="http://dabar.srce.hr/standards/schema/1.0"
                xmlns:dc="http://purl.org/dc/elements/1.1/"
                xmlns:srw_dc="info:srw/schema/1/dc-schema"
                xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="//mods:mods[@ID = 'master']/mods:relatedItem">

        <xsl:choose>

            <!-- Projekt -->
            <xsl:when test="@type='constituent' and not(@displayLabel)">

                <xsl:if test="mods:identifier[@type='local' and normalize-space() != '']">
                    <dc:relation>
                        <xsl:text>info:eu-repo/grantAgreement</xsl:text>
                        <xsl:text>/</xsl:text>
                        <xsl:value-of select="normalize-space(mods:name[@type='corporate' and not(@displayLabel)]/mods:namePart)" />
                        <xsl:text>/</xsl:text>
                        <xsl:value-of select="normalize-space(mods:name[not(@type)]/mods:namePart)" />
                        <xsl:text>/</xsl:text>
                        <xsl:value-of select="normalize-space(mods:identifier[not(@type)])" />
                        <xsl:text>/</xsl:text>
                        <xsl:value-of select="normalize-space(mods:name[@type='corporate' and @displayLabel='jurisdiction']/mods:namePart)" />
                        <xsl:text>/</xsl:text>
                            <xsl:choose>
                                <xsl:when test="mods:titleInfo[@lang = 'eng']">
                                    <xsl:value-of select="normalize-space(mods:titleInfo[not(@type='alternative') and @lang='eng']/mods:title)" />
                                </xsl:when>
                                <xsl:otherwise>
                                    <xsl:value-of select="normalize-space(mods:titleInfo[1][not(@type='alternative')]/mods:title)" />
                                </xsl:otherwise>
                            </xsl:choose>
                        <xsl:if test="mods:titleInfo[@type='alternative']/mods:title">
                            <xsl:text>/</xsl:text>
                            <xsl:value-of select="normalize-space(mods:titleInfo[@type='alternative']/mods:title)" />
                        </xsl:if>
                    </dc:relation>
                </xsl:if>

            </xsl:when>

            <xsl:otherwise>

            </xsl:otherwise>

        </xsl:choose>

    </xsl:template> 

<xsl:template name="replace-string">
    <xsl:param name="text"/>
    <xsl:param name="replace"/>
    <xsl:param name="with"/>
    <xsl:choose>
      <xsl:when test="contains($text,$replace)">
        <xsl:value-of select="substring-before($text,$replace)"/>
        <xsl:value-of select="$with"/>
        <xsl:call-template name="replace-string">
          <xsl:with-param name="text"
select="substring-after($text,$replace)"/>
          <xsl:with-param name="replace" select="$replace"/>
          <xsl:with-param name="with" select="$with"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$text"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

</xsl:stylesheet>

这是我结果的结果

<oai_dc:dc xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.openarchives.org/OAI/2.0/oai_dc/ http://www.openarchives.org/OAI/2.0/oai_dc.xsd">
  <dc:relation>info:eu-repo/grantAgreement/PRE/POST/H200/77777/EU//EXTREMDRON</dc:relation>
</oai_dc:dc>

而不是

信息:EU-回购/ grantAgreement /的 PRE / POST / H200 / 76789 / EUA // EXTRA

但我希望这个:

<dc:relation>info:eu-repo/grantAgreement/**PRE%2FPOST**/H200/76789/EU//EXTRa</dc:relation>

所以我将mods转换为dc,并且我有一个将mods元素放入dc元素的顺序。当一个mods元素值在其中有一个'/'时,我需要将它重新编码为'%2F'(/ - &gt;%2F)

我查看了类似的主题并发现对于XSLT-1.0,您需要一个模板replace-string。问题是我找不到调用此模板的方法

我尝试了以下方法:

<xsl:text>/</xsl:text>
<xsl:value-of select="replace-string(normalize-space(mods:name[@type='corporate' and not(@displayLabel)]/mods:namePart),'/','%2F')" />
<xsl:text>/</xsl:text>

<xsl:text>/</xsl:text>
<xsl:call-template name="replace-string">
  <xsl:with-param name="text" select="normalize-space(mods:titleInfo[not(@type='alternative') and @lang='eng']/mods:title")/>
  <xsl:with-param name="replace" select="'/'" />
  <xsl:with-param name="with" select="'%2F'"/>
</xsl:call-template>
<xsl:text>/</xsl:text>

使用它作为函数的第一种方式将更加用户友好和代码可读。

1 个答案:

答案 0 :(得分:3)

如果你没有用另一个单个字符替换单个字符(在这种情况下你可以使用translate函数),你可以采取一种方法来避免多次写出xsl:call-template,要有一个匹配text()的模板,然后在一个地方进行调用。

<xsl:template match="text()">
<xsl:call-template name="replace-string">
  <xsl:with-param name="text" select="normalize-space(.)"/>
  <xsl:with-param name="replace" select="'/'" />
  <xsl:with-param name="with" select="'%2F'"/>
</xsl:call-template>
</xsl:template>

然后,而不是使用xsl:value-of来输出文本(注意,我调整了你当前的表达式,就像给定的XML一样,它实际上没有输出任何东西)

<xsl:value-of select="normalize-space(mods:titleInfo[not(@type='alternative')][1]/mods:title)" />

将其替换为xsl:apply-templates

 <xsl:apply-templates select="mods:titleInfo[not(@type='alternative')][1]/mods:title/text()" />

另请注意,这意味着您现在也只能在一个地方拥有normalize-space()

编辑:如果您不想如此通用,可以使用mode属性来避免所有文字被更改

所以,文本模板看起来就是这个......

<xsl:template match="text()" mode="replace">
<xsl:call-template name="replace-string">
  <xsl:with-param name="text" select="normalize-space(.)"/>
  <xsl:with-param name="replace" select="'/'" />
  <xsl:with-param name="with" select="'%2F'"/>
</xsl:call-template>
</xsl:template>

xsl:apply-templates看起来像这样......

 <xsl:apply-templates select="mods:titleInfo[not(@type='alternative')][1]/mods:title/text()" mode="replace" />

对于您不想更新的文字,只需省略mode属性。