1

我想用 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>
4

3 回答 3

0

参考您的评论,不,您不应该使用 WHEN/OTHERWISE。覆盖模板是要走的路。

以下 XSLT 1.0 样式表是对您的规则“我需要重命名之后的第一个元素,例如在保持其他元素不变的情况下”的简单解释,而不假设输入文档中的任何特定结构......

<?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 或对输入文档的结构做出某些保证,将会有更简单的解决方案。如果其中任何一个条件为真,请更新您的问题。

于 2012-07-06T08:23:12.733 回答
0

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

/Root/Story/CL/*[1]/name[1]

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

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

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

更新 2:限制选择第一个<name>元素。

于 2012-07-06T07:16:13.250 回答
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>

说明

实际上想要的是重命名具有nameBK元素的任何元素(在本例中为CL)的第一个元素的子元素BK

  1. 身份规则“按原样”复制每个匹配的节点(为其选择执行)。

  2. 标识模板被单个模板覆盖,该模板匹配作为其父元素的第一个子元素name的子元素的任何元素。BK这里name1生成了一个元素,它的属性和主体通过应用模板被复制而不改变(因为它们被唯一的另一个模板匹配和处理——身份规则)。

于 2012-07-06T13:04:48.130 回答