通过xsl根据子元素的部分值修改元素

时间:2012-06-05 03:00:10

标签: xslt xslt-1.0

我有以下XML 1.0代码

<oldEle userlabel="label1">
    <ele1>%02d.jpeg</ele1>
</oldEle>

<oldEle userlabel="label2">
    <ele1>%02d.tiff</ele1>
</oldEle>

我想使用xsl v1.0将oldEle更改为每个oldEle的jpeg和tiff。基本上我希望xsl这样做:

<JPEG userlabel="label1">
    <ele1>%02d.jpeg</ele1>
</JPEG>

<TIFF userlabel="label2">
    <ele1>%02d.tiff</ele1>
</TIFF>

我尝试了以下但是它无效:

<xsl:template match="/oldEle">
    <xsl:for-each select="/oldEle">
    <xsl:if test="contains(/oldEle/ele1,'jpeg')">
        <JPEG>
          <xsl:apply-templates select="@*|node()"/>
        </JPEG>      
    </xsl:if>      
    </xsl:for-each>
</xsl:template>

谢谢!

2 个答案:

答案 0 :(得分:0)

如果你能保证 ele1 元素只包含一个句号,你可以使用xpath函数 substring-after 提取文件扩展名,然后使用 xsl:element 函数用于创建具有该名称的新元素

<xsl:element name="{substring-after(ele1, '.')}">

然而,需要额外的复杂性,因为你需要将它转换为大写,而在XSLT1.0中,这将通过繁琐的翻译函数来实现

<xsl:element 
   name="{translate(
     substring-after(ele1, '.'), 
     'abcdefghijklmnopqrstuvwxyz', 
     'ABCDEFGHIJKLMNOPQRSTUVWXYZ')}">

另外需要注意的是,您在/oldEle上匹配,这意味着 oldEle 是您XML的根元素。因为在格式良好的XML中只能有一个根元素,所以这可能不是你想要的。

这是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="oldEle[contains(ele1, '.')]">
      <xsl:element name="{translate(substring-after(ele1, '.'), 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')}">
         <xsl:apply-templates select="@*|node()"/>
      </xsl:element>
   </xsl:template>

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

应用于以下XML

<root>
   <oldEle userlabel="label1">
      <ele1>%02d.jpeg</ele1>
   </oldEle>
   <oldEle userlabel="label2">
      <ele1>%02d.tiff</ele1>
   </oldEle>
</root>

以下是输出

<root>
   <JPEG userlabel="label1">
      <ele1>%02d.jpeg</ele1>
   </JPEG>
   <TIFF userlabel="label2">
      <ele1>%02d.tiff</ele1>
   </TIFF>
</root>

如果 ele1 包含多个句号,则XSLT会失败。例如,请考虑以下XML

<root>
   <oldEle userlabel="label1">
      <ele1>test.image1.jpeg</ele1>
   </oldEle>
   <oldEle userlabel="label2">
      <ele1>test.image2.tiff</ele1>
   </oldEle>
</root>

在这种情况下,在XSLT1.0中,您可能需要一个递归的命名模板来提取文件扩展名。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="oldEle[contains(ele1, '.')]">
      <xsl:variable name="extension">
         <xsl:call-template name="getExtension">
            <xsl:with-param name="text" select="ele1"/>
         </xsl:call-template>
      </xsl:variable>

      <xsl:element name="{translate($extension, 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')}">
         <xsl:apply-templates select="@*|node()"/>
      </xsl:element>
   </xsl:template>

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

   <xsl:template name="getExtension">
      <xsl:param name="text"/>
      <xsl:param name="delimiter" select="'.'"/>
      <xsl:choose>
         <xsl:when test="contains($text, $delimiter)">
            <xsl:call-template name="getExtension">
               <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
               <xsl:with-param name="delimiter" select="$delimiter"/>
            </xsl:call-template>
         </xsl:when>
         <xsl:otherwise>
            <xsl:value-of select="$text"/>
         </xsl:otherwise>
      </xsl:choose>
   </xsl:template>
</xsl:stylesheet>

这也会产生相同的输出。

答案 1 :(得分:0)

这是一个非递归和更高效的XSLT 1.0解决方案,可以成功地使用任意数量的图像格式扩展,假设它们是静态的

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <my:suffixes>
  <s>jpeg</s><s>JPEG</s>
  <s>tiff</s><s>TIFF</s>
  <s>giv</s><s>GIV</s>
  <s>png</s><s>PNG</s>
 </my:suffixes>

 <xsl:variable name="vSufs" select="document('')/*/my:suffixes/s"/>

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

 <xsl:template match="*">
   <xsl:variable name="vSufFound" select=
    "$vSufs[position() mod 2 = 1]
         [substring(translate(current()/ele1, ., ''),
                    string-length(translate(current()/ele1, ., ''))
                    )
         =
          '.'
         ]"/>
   <xsl:choose>
     <xsl:when test="not($vSufFound)">
      <xsl:call-template name="identity"/>
     </xsl:when>
     <xsl:otherwise>
       <xsl:element name="{$vSufFound/following-sibling::s[1]}">
         <xsl:apply-templates select="node()|@*"/>
       </xsl:element>
     </xsl:otherwise>
   </xsl:choose>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时

<t>
    <oldEle userlabel="label1">
        <ele1>%02d.jpeg</ele1>
    </oldEle>
    <oldEle userlabel="label2">
        <ele1>%02d.tiff</ele1>
    </oldEle>
</t>

产生了想要的正确结果:

<t>
   <JPEG userlabel="label1">
      <ele1>%02d.jpeg</ele1>
   </JPEG>
   <TIFF userlabel="label2">
      <ele1>%02d.tiff</ele1>
   </TIFF>
</t>

应用于以下XML文档时(ele 的字符串值中存在多个点字符:

<root>
    <oldEle userlabel="label1">
        <ele1>test.image1.jpeg</ele1>
    </oldEle>
    <oldEle userlabel="label2">
        <ele1>test.image2.tiff</ele1>
    </oldEle>
</root>

再次产生正确的结果:

<root>
   <JPEG userlabel="label1">
      <ele1>test.image1.jpeg</ele1>
   </JPEG>
   <TIFF userlabel="label2">
      <ele1>test.image2.tiff</ele1>
   </TIFF>
</root>

<强>解释

在此转换中,我们使用以下XPath 1.0表达式来实现标准的XPath 2.0 ends-with($t, $suf)函数:

$suf = substring($t, string-length($t) - string-length($suf) +1)