仅重命名第一个子元素

时间:2012-07-06 07:12:49

标签: xml xslt

我想用XSL选择并重命名第一个子元素。但它并不是第一个孩子,它更像是第一个孩子的第一个节点。

XML看起来像这样:

<Root><Story>
 <CL>
  <BK>
   <name>...</name>
   <Address>...</Address>
  </BK> 
  <BK>
   <name>...</name>
   <Address>...</Address>
 </BK> 
 <BK>
   <name>...</name>
   <Address>...</Address>
  </BK> 
 </CL>
 <CL>
  <BK>
   <name>...</name>
   <Address>...</Address>
  </BK> 
  <BK>
   <name>...</name>
   <Address>...</Address>
 </BK> 
 <BK>
   <name>...</name>
   <Address>...</Address>
  </BK> 
 </CL>
</Story></Root>

我需要重新命名<name>之后的第一个<CL>元素,例如<name1>,同时保留其他<name>元素:

<Root><Story>
 <CL>
  <BK>
   <name1>...</name1>
   <Address>...</Address>
  </BK> 
  <BK>
   <name>...</name>
   <Address>...</Address>
 </BK> 
 <BK>
   <name>...</name>
   <Address>...</Address>
  </BK> 
 </CL>
 <CL>
  <BK>
   <name1>...</name1>
   <Address>...</Address>
  </BK> 
  <BK>
   <name>...</name>
   <Address>...</Address>
 </BK> 
 <BK>
   <name>...</name>
   <Address>...</Address>
  </BK> 
 </CL>
</Story></Root>

3 个答案:

答案 0 :(得分:0)

假设您的问题是关于如何选择正确的元素(而不是在找到它们后如何替换它们),则以下XPath表达式会选择每个元素的第一个子元素中的第一个<name>元素。 {1}}元素:

<CL>

请注意,在/Root/Story/CL/*[1]/name[1] 下,如何选择任意元素(<CL>)。此选择仅限于*的父<CL>元素中的第一个此类元素。

更新:嵌入到XSLT中,然后可以使用以下模板重命名该元素:

[1]

更新2:限制选择第一个<xsl:template match="/Root/Story/CL/*[1]/name[1]"> <name1><xsl:apply-templates select="node()|@*"/></name1> </xsl:template> 元素。

答案 1 :(得分:0)

参考您的评论,不,您不应该使用WHEN / OTHERWISE。覆盖模板是最佳选择。

以下XSLT 1.0样式表是对规则的简单解释&#34;我需要重命名后的第一个元素,例如将其他元素保留为&#34;,而不假设任何特定结构输入文件......

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

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

<xsl:template match="name[(preceding::name | ancestor::CL)[last()]/self::CL]">
 <name1>
  <xsl:apply-templates select="@*|node()"/>
 </name1>
</xsl:template>

</xsl:stylesheet>

注意

如果您可以使用XSLT 2.0或对输入文档的结构做出某些保证,那么将会有更简单的解决方案。如果其中任何一个条件成立,请更新您的问题。

答案 2 :(得分:0)

这是一个完整而简短的解决方案

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

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

 <xsl:template match="BK[1]/name">
  <name1>
   <xsl:apply-templates select="@*|node()"/>
  </name1>
 </xsl:template>
</xsl:stylesheet>

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

<Root><Story>
     <CL>
      <BK>
       <name>...</name>
       <Address>...</Address>
      </BK>
      <BK>
       <name>...</name>
       <Address>...</Address>
     </BK>
     <BK>
       <name>...</name>
       <Address>...</Address>
      </BK>
     </CL>
     <CL>
      <BK>
       <name>...</name>
       <Address>...</Address>
      </BK>
      <BK>
       <name>...</name>
       <Address>...</Address>
     </BK>
     <BK>
       <name>...</name>
       <Address>...</Address>
      </BK>
     </CL>
</Story></Root>

产生了想要的正确结果:

<Root>
   <Story>
      <CL>
         <BK>
            <name1>...</name1>
            <Address>...</Address>
         </BK>
         <BK>
            <name>...</name>
            <Address>...</Address>
         </BK>
         <BK>
            <name>...</name>
            <Address>...</Address>
         </BK>
      </CL>
      <CL>
         <BK>
            <name1>...</name1>
            <Address>...</Address>
         </BK>
         <BK>
            <name>...</name>
            <Address>...</Address>
         </BK>
         <BK>
            <name>...</name>
            <Address>...</Address>
         </BK>
      </CL>
   </Story>
</Root>

<强>解释

实际需要的是重命名具有name个孩子的任何元素(在这种情况下只是BK)的第一个CL元素的BK子元素。 / p>

  1. identity rule 复制每个匹配的节点(选择执行该节点)“按原样”。

  2. 标识模板被匹配任何name元素的单个模板覆盖,该元素是{1}元素的子元素,该元素是其父元素的第一个子元素。这里生成一个BK元素,只需应用模板即可复制其属性和主体(因为它们仅由其他模板匹配和处理 - 身份规则)。