英文:
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.
<root>
<a>
<b type="Test"></b>
</a>
<c></c>
<d>
</d>
<e>
<f>Test1</f>
<f>Test2</f>
</e>
<e>
<f>Test3</f>
<f>Test4</f>
</e>
<e>
<f>Test5</f>
</e>
<a>
<b type="Rest"></b>
</a>
<c></c>
<d>
</d>
<e>
<f>Rest1</f>
<f>Rest2</f>
</e>
<e>
<f>Rest3</f>
<f>Rest4</f>
</e>
<e>
<f>Rest5</f>
</e>
<a>
<b type="Host"></b>
</a>
<c></c>
<d>
</d>
<e>
<f>Hest1</f>
<f>Hest2</f>
</e>
<e>
<f>Hest3</f>
<f>Hest4</f>
</e>
<e>
<f>Hest5</f>
</e>
<a>
<b type="Test"></b>
</a>
<c></c>
<d>
</d>
<e>
<f>Test6</f>
<f>Test7</f>
</e>
<e>
<f>Test8</f>
<f>Test9</f>
</e>
<e>
<f>Test10</f>
</e>
<a>
<b type="Fest"></b>
</a>
<c></c>
<d>
</d>
<e>
<f>Fest1</f>
<f>Fest2</f>
</e>
<e>
<f>Fest3</f>
<f>Fest4</f>
</e>
<e>
<f>Fest5</f>
</e>
</root>
The expectation is it will fetch specific type tag<a> which can occurs n numbers in xml and the below <f> 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
<b type="Rest"></b>
<f>Rest1</f>
<f>Rest2</f>
<f>Rest3</f>
<f>Rest4</f>
<f>Rest5</f>
<f>Fest1</f>
<f>Fest2</f>
<f>Fest3</f>
<f>Fest4</f>
<f>Fest5</f>
Or
<b type="Test"></b>
<f>Test1</f>
<f>Test2</f>
<f>Test3</f>
<f>Test4</f>
<f>Test5</f>
<f>Test6</f>
<f>Test7</f>
<f>Test8</f>
<f>Test9</f>
<f>Test10</f>
It will select the specific type and display all the <f> 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:
<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 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:
<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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论