【问题标题】:Renaming Tags via XSLT for Similar Tag Pattern通过 XSLT 重命名标签以获得相似的标签模式
【发布时间】:2013-12-12 09:24:33
【问题描述】:

我有一个 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>

以前,当标签类似于&lt;FlightDetails&gt; and &lt;CouponNumber&gt; 时,我在 XSLT 中使用了“复制”功能。随着标签被重命名,使用 xslt 实现这一目标的最简单方法是什么? XSLT:

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

【问题讨论】:

  • " 使用 xslt 实现这一目标的最简单方法是什么?" 最简单 方法取决于您的 XML 中还有什么(或可能是)。您不必总是通过名称(或名称的一部分)来引用元素;有时根据上下文选择节点更方便。

标签: xml xslt transformation


【解决方案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. &lt;xsl:element name="{translate(name(), '01234567890', '')}"&gt; 然后重新创建没有尾随数字的元素。

【讨论】:

    【解决方案2】:

    如果您不希望元素名称保持不变,则不能再使用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>
    

    【讨论】:

    • &lt;xsl:element name="ServiceClass"&gt; 是一种非常冗长的表示&lt;ServiceClass&gt; 的方式。 :)
    • 我同意。而且,它清楚地表明样式表生成了新元素。
    • &lt;ServiceClass&gt; 也是如此。 ;) 您在模板中编写的每个元素都是新创建的。甚至 &lt;xsl:copy&gt; 从头开始​​创建所有元素。
    • 请不要挑剔我的选择。当然,您可以重新生成任何元素,但对我来说,xsl:element 的目的更明显——即使否则它会更简洁。
    • 我曾经这样做过,但我发现在结束元素 (&lt;/xsl:element&gt;) 处它正在关闭哪个元素并不总是很明显,这对于大型样式表可能会非常混乱。 &lt;/ServiceClass&gt;(在这种情况下)使它更清晰。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-17
    • 1970-01-01
    相关资源
    最近更新 更多