用XSLT替换Node文本?

时间:2011-11-04 09:06:21

标签: xml xslt

下面是我的XML文件,用于存储数据 -

<Locations>
   <location>
      <place>Newyork</place>
      <dt>01-Dec-2011</dt>
   </location>
   <location>
      <place>Berlin</place>
      <dt>02-Dec-2011</dt>
   </location>
   <location>
      <place>Tokyo</place>
      <dt>04-Dec-2011</dt>
   </location>
</Location>

我想要实现的是 -

如果重新安排访问,我想替换<dt>代码日期值。例如- 如果柏林的访问日期发生变化,存储在<dt>标签中,那么如何编辑/替换它 在使用XSLT的XML文件中..?提前谢谢 - 约翰

3 个答案:

答案 0 :(得分:5)

此转换显示如何使用全局参数(此处使用内联元素建模)指定(可能是多个)更新

<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:updates>
  <update place="Berlin" dt="11-Dec-2011"/>
 </my:updates>

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

 <xsl:template match=
  "location
     [place = document('')/*/my:updates/update/@place]
       /dt/text()
  ">
  <xsl:value-of select=
    "document('')/*/my:updates/update
                      [@place = current()/../../place]
                        /@dt
    "/>
 </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档(已更正以使其格式正确):

<Locations>
   <location>
      <place>Newyork</place>
      <dt>01-Dec-2011</dt>
   </location>
   <location>
      <place>Berlin</place>
      <dt>02-Dec-2011</dt>
   </location>
   <location>
      <place>Tokyo</place>
      <dt>04-Dec-2011</dt>
   </location>
</Locations>

产生了想要的正确结果

<Locations>
   <location>
      <place>Newyork</place>
      <dt>01-Dec-2011</dt>
   </location>
   <location>
      <place>Berlin</place>
      <dt>11-Dec-2011</dt>
   </location>
   <location>
      <place>Tokyo</place>
      <dt>04-Dec-2011</dt>
   </location>
</Locations>

<强>解释

  1. 身份规则“按原样”复制每个节点。

  2. 只有一个覆盖模板 - 匹配dt兄弟的字符串值具有相应place的任何my:updates/update的文本节点子项元素。在此模板中,我们输出此对应dt元素的my:updates/update属性的值。

  3. 请注意:在realworld转换中,内联my:updates元素将更好地被外部全局参数替换。阅读您的XSLT处理器文档,了解如何将外部参数传递给转换 - 这取决于实现。

    更新:由于OP发现很难将此解决方案转换为使用全局,外部传递xsl:param的解决方案,因此这是转换后的解决方案:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:ext="http://exslt.org/common">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:param name="pUpdates">
      <update place="Berlin" dt="11-Dec-2011"/>
     </xsl:param>
    
     <xsl:variable name="vUpdates" select=
         "ext:node-set($pUpdates)/*"/>
    
     <xsl:template match="node()|@*">
         <xsl:copy>
           <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
     </xsl:template>
    
     <xsl:template match="dt/text()">
      <xsl:choose>
          <xsl:when test="../../place=$vUpdates/@place">
           <xsl:value-of select=
               "$vUpdates[@place = current()/../../place]/@dt"/>
          </xsl:when>
          <xsl:otherwise>
           <xsl:value-of select="."/>
          </xsl:otherwise>
      </xsl:choose>
     </xsl:template>
    </xsl:stylesheet>
    

    当在同一个XML文档(上面)上应用此转换时,会生成相同的正确和想要的结果

    <Locations>
       <location>
          <place>Newyork</place>
          <dt>01-Dec-2011</dt>
       </location>
       <location>
          <place>Berlin</place>
          <dt>11-Dec-2011</dt>
       </location>
       <location>
          <place>Tokyo</place>
          <dt>04-Dec-2011</dt>
       </location>
    </Locations>
    

    请注意:在此解决方案中,xsl:param的值仍然是硬编码的,这是我们使用ext:node-set()扩展功能的唯一原因。如果参数确实是从外部传递的,那么从RTF到常规树的转换不是必需的,参数应该直接引用。

    此外,在XSLT 1.0中,我们必须匹配更多不精确并在模板正文中使用比较(xsl:choose)。这是因为在XSLT 1.0中,不允许在匹配模式中引用变量/参数。

    在XSLT 2.0中,此限制已被取消,因此我们可以进行更简单的转换:

    <xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:param name="pUpdates">
      <update place="Berlin" dt="11-Dec-2011"/>
     </xsl:param>
    
     <xsl:template match="node()|@*">
         <xsl:copy>
           <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
     </xsl:template>
    
     <xsl:template match=
       "location[place=$pUpdates/*/@place]/dt/text()">
           <xsl:value-of select=
               "$pUpdates/*[@place = current()/../../place]/@dt"/>
     </xsl:template>
    </xsl:stylesheet>
    

答案 1 :(得分:2)

身份模板将复制文档:

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

然后,您只能为要更改的部分制作其他模板。

示例(未经测试):

<xsl:template match="//location/dt[preceding-sibling::place='Berlin']">
    <dt>Your date</dt>
</xsl:template>

答案 2 :(得分:1)

真正的问题是,您如何检查访问是否重新安排?我看到它的方式,你有三个选择:

  • 将重新安排的日期存储在辅助XML中,并使用XPath document函数从中读取;
  • 以编程方式生成XSLT样式表,其中包含已更正的更正或
  • 使用XSLT扩展函数或扩展元素(函数可能就足够了)以其他语言执行检查。例如Java。

编辑 - 或者遵循Krab的优秀建议:以一种允许您将数据传递给静态样式表的方式使用XSLT参数。