Creating XSLT from specific XML

huangapple go评论54阅读模式
英文:

Creating XSLT from specific XML

问题

下面是根据您提供的输入XML生成的XSLT,以按您的预期输出特定类型的标签<a>和相应的<f>子标签:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="root">
  <xsl:apply-templates select="a"/>
</xsl:template>

<xsl:template match="a">
  <xsl:variable name="currentType" select="b/@type"/>
  <xsl:apply-templates select="following-sibling::*[preceding-sibling::a[1][b/@type = $currentType]]"/>
</xsl:template>

<xsl:template match="e/f">
  <xsl:copy-of select="."/>
</xsl:template>

</xsl:stylesheet>

这个XSLT将根据特定类型的<a>标签和相应的<f>子标签生成输出,其中标签顺序不是固定的,但会按特定类型分组。

英文:

I am new to XSLT. Need help on creating XSLT from below input XML.

&lt;root&gt;
 &lt;a&gt;
    &lt;b type=&quot;Test&quot;&gt;&lt;/b&gt;
  &lt;/a&gt;
  &lt;c&gt;&lt;/c&gt;
  &lt;d&gt;
  &lt;/d&gt;
  &lt;e&gt;
    &lt;f&gt;Test1&lt;/f&gt;
    &lt;f&gt;Test2&lt;/f&gt;
  &lt;/e&gt;
  &lt;e&gt;
    &lt;f&gt;Test3&lt;/f&gt;
    &lt;f&gt;Test4&lt;/f&gt;
  &lt;/e&gt;
  &lt;e&gt;
    &lt;f&gt;Test5&lt;/f&gt;
  &lt;/e&gt;

  &lt;a&gt;
    &lt;b type=&quot;Rest&quot;&gt;&lt;/b&gt;
  &lt;/a&gt;
  &lt;c&gt;&lt;/c&gt;
  &lt;d&gt;
  &lt;/d&gt;
  &lt;e&gt;
    &lt;f&gt;Rest1&lt;/f&gt;
    &lt;f&gt;Rest2&lt;/f&gt;
  &lt;/e&gt;
  &lt;e&gt;
    &lt;f&gt;Rest3&lt;/f&gt;
    &lt;f&gt;Rest4&lt;/f&gt;
  &lt;/e&gt;
  &lt;e&gt;
    &lt;f&gt;Rest5&lt;/f&gt;
  &lt;/e&gt;

  &lt;a&gt;
    &lt;b type=&quot;Host&quot;&gt;&lt;/b&gt;
  &lt;/a&gt;
  &lt;c&gt;&lt;/c&gt;
  &lt;d&gt;
  &lt;/d&gt;
  &lt;e&gt;
    &lt;f&gt;Hest1&lt;/f&gt;
    &lt;f&gt;Hest2&lt;/f&gt;
  &lt;/e&gt;
  &lt;e&gt;
    &lt;f&gt;Hest3&lt;/f&gt;
    &lt;f&gt;Hest4&lt;/f&gt;
  &lt;/e&gt;
  &lt;e&gt;
    &lt;f&gt;Hest5&lt;/f&gt;
  &lt;/e&gt;

  &lt;a&gt;
    &lt;b type=&quot;Test&quot;&gt;&lt;/b&gt;
  &lt;/a&gt;
  &lt;c&gt;&lt;/c&gt;
  &lt;d&gt;
  &lt;/d&gt;
  &lt;e&gt;
    &lt;f&gt;Test6&lt;/f&gt;
    &lt;f&gt;Test7&lt;/f&gt;
  &lt;/e&gt;
  &lt;e&gt;
    &lt;f&gt;Test8&lt;/f&gt;
    &lt;f&gt;Test9&lt;/f&gt;
  &lt;/e&gt;
  &lt;e&gt;
    &lt;f&gt;Test10&lt;/f&gt;
  &lt;/e&gt;

  &lt;a&gt;
    &lt;b type=&quot;Fest&quot;&gt;&lt;/b&gt;
  &lt;/a&gt;
  &lt;c&gt;&lt;/c&gt;
  &lt;d&gt;
  &lt;/d&gt;
  &lt;e&gt;
    &lt;f&gt;Fest1&lt;/f&gt;
    &lt;f&gt;Fest2&lt;/f&gt;
  &lt;/e&gt;
  &lt;e&gt;
    &lt;f&gt;Fest3&lt;/f&gt;
    &lt;f&gt;Fest4&lt;/f&gt;
  &lt;/e&gt;
  &lt;e&gt;
  &lt;f&gt;Fest5&lt;/f&gt;
  &lt;/e&gt;

&lt;/root&gt;

The expectation is it will fetch specific type tag&lt;a&gt; which can occurs n numbers in xml and the below &lt;f&gt; child tags. child tags should be merged. Tag positions are not constant. only constant pattern is "specific type and tags below that type until the next type".

The Output will be

&lt;b type=&quot;Rest&quot;&gt;&lt;/b&gt;
&lt;f&gt;Rest1&lt;/f&gt;
&lt;f&gt;Rest2&lt;/f&gt; 
&lt;f&gt;Rest3&lt;/f&gt; 
&lt;f&gt;Rest4&lt;/f&gt; 
&lt;f&gt;Rest5&lt;/f&gt; 
&lt;f&gt;Fest1&lt;/f&gt; 
&lt;f&gt;Fest2&lt;/f&gt; 
&lt;f&gt;Fest3&lt;/f&gt; 
&lt;f&gt;Fest4&lt;/f&gt; 
&lt;f&gt;Fest5&lt;/f&gt;

Or

&lt;b type=&quot;Test&quot;&gt;&lt;/b&gt;
&lt;f&gt;Test1&lt;/f&gt; 
&lt;f&gt;Test2&lt;/f&gt; 
&lt;f&gt;Test3&lt;/f&gt; 
&lt;f&gt;Test4&lt;/f&gt; 
&lt;f&gt;Test5&lt;/f&gt; 
&lt;f&gt;Test6&lt;/f&gt; 
&lt;f&gt;Test7&lt;/f&gt; 
&lt;f&gt;Test8&lt;/f&gt; 
&lt;f&gt;Test9&lt;/f&gt; 
&lt;f&gt;Test10&lt;/f&gt;

It will select the specific type and display all the &lt;f&gt; under that type.

答案1

得分: 0

XSLT 3中的解决方案使用累加器(accumulators),即使在流式处理中也能工作:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0"
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  exclude-result-prefixes="#all"
  expand-text="yes">
  
  <xsl:param name="type" as="xs:string" select="'Rest'"/>
  
  <xsl:mode on-no-match="shallow-skip" use-accumulators="found first-found" streamable="yes"/>
  
  <xsl:accumulator name="first-found" as="xs:boolean" initial-value="false()" streamable="yes">
    <xsl:accumulator-rule match="a/b[@type = $type]" select="if (not($value)) then true() else false()"/>
  </xsl:accumulator>
  
  <xsl:accumulator name="found" as="xs:boolean" initial-value="false()" streamable="yes">
    <xsl:accumulator-rule match="a/b[@type = $type]" select="true()"/>
    <xsl:accumulator-rule match="a/b[not(@type = $type)]" select="false()"/>
  </xsl:accumulator>

  <xsl:output indent="yes"/>

  <xsl:template match="*/f[accumulator-before('found')] | a/b[@type = $type][accumulator-before('first-found')])">
    <xsl:copy-of select="."/>
  </xsl:template>

</xsl:stylesheet>

XSLT 1.0的解决方案使用了键(key)来匹配a元素后面的f元素:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  
  <xsl:param name="type">Rest</xsl:param>
  
  <xsl:output method="xml" indent="yes"/>
  
  <xsl:key name="group" match="root/e/f" use="generate-id(../preceding-sibling::a[b/@type][1])"/>
  
  <xsl:template match="/">
    <xsl:apply-templates select="root/a[b/@type = $type]"/>
  </xsl:template>
  
  <xsl:template match="a">
    <xsl:if test="position() = 1">
      <xsl:copy-of select="b"/>
    </xsl:if>
    <xsl:copy-of select="key('group', generate-id())"/>
  </xsl:template>

</xsl:stylesheet>
英文:

Easy in XSLT 3 with accumulators, works that way even for streamed processing:

&lt;xsl:stylesheet xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot; version=&quot;3.0&quot;
  xmlns:xs=&quot;http://www.w3.org/2001/XMLSchema&quot;
  exclude-result-prefixes=&quot;#all&quot;
  expand-text=&quot;yes&quot;&gt;
  
  &lt;xsl:param name=&quot;type&quot; as=&quot;xs:string&quot; select=&quot;&#39;Rest&#39;&quot;/&gt;

  &lt;xsl:mode on-no-match=&quot;shallow-skip&quot; use-accumulators=&quot;found first-found&quot; streamable=&quot;yes&quot;/&gt;

  &lt;xsl:accumulator name=&quot;first-found&quot; as=&quot;xs:boolean&quot; initial-value=&quot;false()&quot; streamable=&quot;yes&quot;&gt;
    &lt;xsl:accumulator-rule match=&quot;a/b[@type = $type]&quot; select=&quot;if (not($value)) then true() else false()&quot;/&gt;
  &lt;/xsl:accumulator&gt;
  
  &lt;xsl:accumulator name=&quot;found&quot; as=&quot;xs:boolean&quot; initial-value=&quot;false()&quot; streamable=&quot;yes&quot;&gt;
    &lt;xsl:accumulator-rule match=&quot;a/b[@type = $type]&quot; select=&quot;true()&quot;/&gt;
    &lt;xsl:accumulator-rule match=&quot;a/b[not(@type = $type)]&quot; select=&quot;false()&quot;/&gt;
  &lt;/xsl:accumulator&gt;

  &lt;xsl:output indent=&quot;yes&quot;/&gt;
  
  &lt;xsl:template match=&quot;*/f[accumulator-before(&#39;found&#39;)] | a/b[@type = $type][accumulator-before(&#39;first-found&#39;)]&quot;&gt;
    &lt;xsl:copy-of select=&quot;.&quot;/&gt;
  &lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;

XSLT 3 is implemented by Saxon from Saxonica on various platforms (e.g. Java with Saxon HE or higher 10, 11, 12, .NET with Saxon HE or higher 10, .NET 6/7 with SaxonCS, Python with SaxonC 11 or 12, browser and Node.js with SaxonJS 2.5) and by Altova.

With XSLT 1.0 you can try sibling recursion but it might be easier to use a key that allows grabbing the f elements following the a[b/@type = $type] and then just process those a elements, output the first and for each output the f elements the key function call finds:

&lt;xsl:stylesheet
	xmlns:xsl=&quot;http://www.w3.org/1999/XSL/Transform&quot;
	version=&quot;1.0&quot;&gt;
  
  &lt;xsl:param name=&quot;type&quot;&gt;Rest&lt;/xsl:param&gt;

  &lt;xsl:output method=&quot;xml&quot; indent=&quot;yes&quot;/&gt;
  
  &lt;xsl:key name=&quot;group&quot; match=&quot;root/e/f&quot; use=&quot;generate-id(../preceding-sibling::a[b/@type][1])&quot;/&gt;

  &lt;xsl:template match=&quot;/&quot;&gt;
    &lt;xsl:apply-templates select=&quot;root/a[b/@type = $type]&quot;/&gt;
  &lt;/xsl:template&gt;
  
  &lt;xsl:template match=&quot;a&quot;&gt;
    &lt;xsl:if test=&quot;position() = 1&quot;&gt;
      &lt;xsl:copy-of select=&quot;b&quot;/&gt;
    &lt;/xsl:if&gt;
    &lt;xsl:copy-of select=&quot;key(&#39;group&#39;, generate-id())&quot;/&gt;
  &lt;/xsl:template&gt;

&lt;/xsl:stylesheet&gt;

huangapple
  • 本文由 发表于 2023年5月21日 02:58:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/76296897.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定