草庐IT

xml - XSLT - 在分隔符上分解节点

coder 2024-06-28 原文

我需要一个 XSLT 1.0 来分解分隔符上的 XML 节点并创建单独的节点。 例如,如果分隔符是“_”并且 XML 是:

<root>
    <a_b_c>hello<a_b_c>
    <a_b_c1>world</a_b_c1>
</root>

结果 XML 应该是:

<root>
    <a>
        <b>
            <c>hello</c>
            <c1>world</c1>
        </b>
    </a>
</root>

不包含分隔符的节点应按原样输出。 在 XSLT1.0 中我真的需要这个 感谢您的帮助。

最佳答案

这个转换:

<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:key name="kSameNameAdj" match="*"
  use="concat(generate-id(..),
              '+',
              generate-id(preceding-sibling::*[not(name()=name(current()))][1])
              )"/>

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

 <xsl:template match="/">
  <xsl:variable name="vrtfPass1">
   <xsl:apply-templates select="node()"/>
  </xsl:variable>

  <xsl:apply-templates select="ext:node-set($vrtfPass1)" mode="compress"/>
 </xsl:template>

 <xsl:template name="explode" match=
  "*[contains(name(),'_')
   and not(substring(name(),1,1)='_')
   and not(substring(name(), string-length(name()))='_')
    ]">
    <xsl:param name="pName" select="name()"/>
    <xsl:param name="pText" select="text()"/>

  <xsl:choose>
   <xsl:when test="not($pName)">
    <xsl:value-of select="$pText"/>
   </xsl:when>
   <xsl:otherwise>
      <xsl:element name="{substring-before(concat($pName, '_'), '_')}">
       <xsl:call-template name="explode">
         <xsl:with-param name="pName" select="substring-after($pName, '_')"/>
         <xsl:with-param name="pText" select="$pText"/>
       </xsl:call-template>
      </xsl:element>
   </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

  <xsl:template match="/" name="fold" mode="compress">
  <xsl:param name="pDoc" select="/"/>

  <xsl:choose>
    <xsl:when test="not($pDoc//*[name()=name(following-sibling::*[1])])">
      <xsl:copy-of select="$pDoc"/>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="vrtfThisPass">
        <xsl:apply-templates select="$pDoc/*" mode="compress"/>
      </xsl:variable>

      <xsl:call-template name="fold">
        <xsl:with-param name="pDoc" select="ext:node-set($vrtfThisPass)"/>
      </xsl:call-template>
    </xsl:otherwise>
  </xsl:choose>
 </xsl:template>

 <xsl:template match="node()|@*" mode="compress">
   <xsl:copy>
     <xsl:apply-templates select="@*|node()[1]" mode="compress"/>
   </xsl:copy>
   <xsl:apply-templates select="following-sibling::node()[1]" mode="compress"/>
 </xsl:template>

 <xsl:template match="*[name()=name(following-sibling::*[1])]" mode="compress">
  <xsl:element name="{name()}">
    <xsl:apply-templates mode="compress" select=
    "key('kSameNameAdj',
          concat(generate-id(..),
                 '+',generate-id(preceding-sibling::*)
                 )
         )/node()"/>
  </xsl:element>
  <xsl:apply-templates mode="compress" select=
  "key('kSameNameAdj',
          concat(generate-id(..),
                 '+',generate-id(preceding-sibling::*)
                 )
         )
          [last()]/following-sibling::node()[1]
   "/>
 </xsl:template>
</xsl:stylesheet>

应用于以下 XML 文档时(提供的文档,扩展后更具挑战性):

<root>
   <x>This is:</x>
     <a_b_c>hello</a_b_c>
     <a_b_c_d>my</a_b_c_d>
     <a_b_c1>wonderful</a_b_c1>
     <a_b_c>world</a_b_c>
     <a_b>!</a_b>
   <y>The End</y>
</root>

产生想要的、正确的结果:

<root>
   <x>This is:</x>
   <a>
      <b>
         <c>hello<d>my</d>
         </c>
         <c1>wonderful</c1>
         <c>world</c>!</b>
   </a>
   <y>The End</y>
</root>

解释:

.1。 这是一个多 channel 转换。 第一遍将 XML 文档转换为:

<root>
   <x>This is:</x>
   <a>
      <b>
         <c>hello</c>
      </b>
   </a>
   <a>
      <b>
         <c>
            <d>my</d>
         </c>
      </b>
   </a>
   <a>
      <b>
         <c1>wonderful</c1>
      </b>
   </a>
   <a>
      <b>
         <c>world</c>
      </b>
   </a>
   <a>
      <b>!</b>
   </a>
   <y>The End</y>
</root>

.2。 随后的传递,每个传递将具有相同名称的任何一组相邻元素压缩为具有该名称的单个元素 - 然后递归处理结果,直到不再有任何一组超过一个相邻的 sibling 具有相同名称的元素。

.3。 第一遍使用 identity rule .

.4。 接下来的通行证使用 fine-grade identity “压缩”模式下的模板

关于xml - XSLT - 在分隔符上分解节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11816585/

有关xml - XSLT - 在分隔符上分解节点的更多相关文章

  1. ruby-on-rails - 如何从 format.xml 中删除 <hash></hash> - 2

    我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为

  2. ruby-on-rails - 如何在 Rails 3 中禁用 XML 解析 - 2

    我想禁用HTTP参数的自动XML解析。但我发现命令仅适用于Rails2.x,它们都不适用于3.0:config.action_controller.param_parsers.deleteMime::XML(application.rb)ActionController::Base.param_parsers.deleteMime::XMLRails3.0中的等价物是什么? 最佳答案 根据CVE-2013-0156的最新安全公告你可以将它用于Rails3.0。3.1和3.2ActionDispatch::ParamsParser::

  3. ruby - 如何使用 Nokogiri::XML::Builder 生成动态标签? - 2

    我正在遍历数组中的一组标签名称,我想使用构建器打印每个标签名称,而不是求助于“我认为:builder=Nokogiri::XML::Builder.newdo|xml|fortagintagsxml.tag!tag,somevalendend会这样做,但它只是创建名称为“tag”的标签,并将标签变量作为元素的文本值。有人可以帮忙吗?这个看起来应该比较简单,我刚刚在搜索引擎上找不到答案。我可能没有以正确的方式提问。 最佳答案 尝试以下操作。如果我没记错的话,我添加了一个根节点,因为Nokogiri需要一个。builder=Nokogi

  4. ruby-on-rails - 如何以递归方式将 YAML 文件扁平化为 JSON 对象,其中键是点分隔的字符串? - 2

    例如,如果我有YAML文件en:questions:new:'NewQuestion'other:recent:'Recent'old:'Old'这最终会变成一个json对象,例如{'questions.new':'NewQuestion','questions.other.recent':'Recent','questions.other.old':'Old'} 最佳答案 由于问题是关于在Rails应用程序上使用YAML文件进行i18n,因此值得注意i18ngem提供了一个辅助模块I18n::Backend::Flatten完全像

  5. ruby - 如何让 Nokogiri 解析并返回 XML 文档? - 2

    这是一些奇怪的例子:#!/usr/bin/rubyrequire'rubygems'require'open-uri'require'nokogiri'print"withoutread:",Nokogiri(open('http://weblog.rubyonrails.org/')).class,"\n"print"withread:",Nokogiri(open('http://weblog.rubyonrails.org/').read).class,"\n"运行此返回:withoutread:Nokogiri::XML::Documentwithread:Nokogiri::

  6. 区块链入门教程(6)--WeBASE-Front节点前置服务安装 - 2

    文章目录1.任务背景2.任务目标3.相关知识点4.任务实操4.1安装配置JDK4.2启动FISCOBCOS4.3下载解压WeBASE-Front4.4拷贝sdk证书文件4.5启动节点4.6访问节点4.7检查运行状态5.任务总结1.任务背景FISCOBCOS其实是有控制台管理工具,用来对区块链系统进行各种管理操作。但是对于初学者来说,还是可视化界面更友好,本节就来介绍WeBASE管理平台,这是一款微众银行开源的自研区块链中间件平台,可以降低区块链使用的门槛,大幅提高区块链应用的开发效率。微众银行是腾讯牵头设立的民营银行,在国内民营银行里还是比较出名的。微众银行参与FISCOBCOS生态建设,一定

  7. ruby - 选择包含子节点内文本的父节点 - 2

    基本上我想选择一个节点(div),其中它的子节点(h1,b,h3)包含指定的文本。Childtext1Childtext2...Childtext3我期待的是/html/div/而不是/html/div/h1我在下面有这个,但不幸的是返回了child,而不是div的xpath。expression="//div[contains(text(),'Childtext1')]"doc.xpath(expression)我期待的是/html/div/而不是/html/div/h1那么有没有一种方法可以简单地使用xpath语法来做到这一点? 最佳答案

  8. ruby - 模式加载时出现 Nokogiri::XML::Schema SyntaxError - 2

    我正在尝试加载SAML协议(protocol)架构(具体来说:https://www.oasis-open.org/committees/download.php/3407/oasis-sstc-saml-schema-protocol-1.1.xsd),但在执行此操作之后:schema=Nokogiri::XML::Schema(File.read('saml11_schema.xsd'))我得到这个输出:Nokogiri::XML::SyntaxErrorException:Element'{http://www.w3.org/2001/XMLSchema}element',att

  9. ruby - 删除指定节点之后的所有节点 - 2

    这个问题在这里已经有了答案:Nokogiri:SelectcontentbetweenelementAandB(3个答案)关闭2年前。我正在从url中抓取文本的div,并想删除具有backtotop类的段落下方的所有内容。我在stackoverflow上看到了一段遍历代码片段,看起来很有希望,但我不知道如何将它合并,所以@el只包含第一个p.backtotop之前的所有内容分区我的代码:@doc=Nokogiri::HTML(open(url))@el=@doc.css("div")[0]end遍历片段:doc=Nokogiri::HTML(code)stop_node=doc.css

  10. ruby - 如何从 Chef 说明书中的库访问当前节点? - 2

    我正在尝试为ChefRecipe编写一个库,以简化一些常见的搜索。例如,我希望能够在cookbook/libraries/library.rb中执行类似的操作,然后从同一Recipe中的Recipe中使用它:moduleExampledefself.search_attribute(attribute_name)returnsearch(:nodes,node[attribute_name])endend问题是,在Chef库文件中,node对象或search函数都不可用。似乎可以使用Chef::Search::Query.new().search(...)进行搜索,但我找不到任何可以访

随机推荐