通过XSLT为类似标记模式重命名标记

时间:2013-12-12 09:24:33

标签: xml xslt transformation

我有一个xml:

<FlightDetails1>
                    <CouponNumber1>1</CouponNumber1>
            <ServiceClass1>Y</ServiceClass1>
</FlightDetails1>
<FlightDetails2>
                        <CouponNumber2>2</CouponNumber2>
                        <ServiceClass2>Y</ServiceClass2>
</FlightDetails2>
<FlightDetails3>
                        <CouponNumber3></CouponNumber3>
                        <ServiceClass3>N</ServiceClass3>
</FlightDetails3>

需要将此xml转换为以下格式:

<FlightDetails>
                        <CouponNumber>1</CouponNumber>
            <ServiceClass>Y</ServiceClass>
</FlightDetails>
<FlightDetails>
                        <CouponNumber>2</CouponNumber>
                        <ServiceClass>Y</ServiceClass>
</FlightDetails>
<FlightDetails>
                        <CouponNumber></CouponNumber>
                        <ServiceClass>N</ServiceClass>
</FlightDetails>

以前,当标签类似于<FlightDetails> and <CouponNumber>时,我在XSLT中使用了'copy-of'功能。在重命名标签的情况下,使用xslt实现这一目标的最简单方法是什么? XSLT:

<xsl:output indent="yes"/>
          <xsl:template match="/">
          <xsl:copy-of select="//FlightDetails1"/>
          </xsl:template>

2 个答案:

答案 0 :(得分:1)

这是一个通用版本

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

  <!-- elements whose names end with digits -->
  <xsl:template match="*[
     starts-with(name(), translate(name(), '01234567890', ''))
     and substring-after(name(), translate(name(), '01234567890', ''))
  ]">
    <xsl:element name="{translate(name(), '01234567890', '')}">
      <xsl:apply-templates select="node() | @*" />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

第二个模板匹配所有以数字结尾的元素......

  1. 删除名称中的所有数字

    translate(name(), '01234567890', '') := 'FlightDetails1' -> 'FlightDetails'
    
  2. 确保它与中间数字的元素不匹配

    starts-with('FlightDetails1', 'FlightDetails')     := true
    starts-with('Flight1Details', 'FlightDetails')     := false
    
  3. 检查字符串开头后有什么东西(按照定义,这只能是一个或多个数字,所有其他元素都已经失败了以前的测试)

    substring-after('FlightDetails1', 'FlightDetails') := '1' (evaluates to true)
    

    这样,模板会匹配letters123形式的任何名称元素。

  4. <xsl:element name="{translate(name(), '01234567890', '')}">然后重新创建没有尾随数字的元素。

答案 1 :(得分:0)

如果您不希望元素名称持久存在,则不能再使用copy(或者使用它的方式复制)。

相反,请在单独的模板中匹配这些元素,例如:

<xsl:template match="*[starts-with(name(),'FlightDetails')]">
  <xsl:element name="FlightDetails">
  <!--Further processing-->
  </xsl:element>
</xsl:template>

此模板匹配所有形式的FlightDetails元素,也就是说,无论元素名称末尾的数字如何。然后,使用xsl:element指令创建一个名为“FlightDetails”的新元素。

然后,继续为您希望规范化的其他元素编写类似的模板。请注意,现在apply-templates/已经发挥作用,将其留给处理器决定接下来应用哪个模板。

总结所有这些的样式表(我在输入XMl中添加了root元素以使其格式正确):

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/root">
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="*[starts-with(name(),'FlightDetails')]">
  <xsl:element name="FlightDetails">
     <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<xsl:template match="*[starts-with(name(),'CouponNumber')]">
  <xsl:element name="CouponNumber">
     <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<xsl:template match="*[starts-with(name(),'ServiceClass')]">
  <xsl:element name="ServiceClass">
     <xsl:apply-templates/>
  </xsl:element>
</xsl:template>

<xsl:template match="text()">
  <xsl:copy/>
</xsl:template>

</xsl:stylesheet>

提供以下输出:

<?xml version="1.0" encoding="UTF-8"?>
<FlightDetails>
  <CouponNumber>1</CouponNumber>
  <ServiceClass>Y</ServiceClass>
</FlightDetails>
<FlightDetails>
  <CouponNumber>2</CouponNumber>
  <ServiceClass>Y</ServiceClass>
</FlightDetails>
<FlightDetails>
  <CouponNumber/>
  <ServiceClass>N</ServiceClass>
</FlightDetails>