无法使用分组执行XSLT转换 [英] Not able to do XSLT transformation with grouping
本文介绍了无法使用分组执行XSLT转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我有一个类似的XML,我想将下面的XML转换成不同的格式,但是不能得到确切的输出,但是可以得到输出的一部分
<?xml version="1.0" encoding="UTF-8"?>
<text width="12240" height="15840" orient="">
<p style="TRH2">
<r>Partial Interests</r>
</p>
<p style="TRH4">
<r>5.01Concurrent Interests</r>
</p>
<p style="TRH5">
<r>[1]In General</r>
</p>
<p style="TRH6">
<r>Arabic</r>
</p>
<p style="TRH7">
<r>section</r>
</p>
<p style="TRNormal">
<r>An owner.</r>
</p>
<p style="TRNormal">
<r>On other</r>
</p>
<p/>
<p style="TRH7">
<r>sections</r>
</p>
<p style="TRNormal">
<r>entitled</r>
</p>
<p style="TRNormal">
<r>in which</r>
</p>
<p style="TRH4">
<r>division</r>
</p>
<p style="TRH7">
<r>section3</r>
</p>
<p/>
<p style="TRNormal">
<r>entitled</r>
</p>
<p style="TRNormal">
<r>demo</r>
</p>
<p style="TRH7">
<r>sections4</r>
</p>
<p style="TRNormal">
<r>val demo</r>
</p>
<p style="TRNormal">
<r>val which</r>
</p>
</text>
我想进行XSLT转换,并将上面的输入转换为下面的预期输出
<?xml version="1.0" encoding="UTF-8"?><chapter><title>Partial Interests</title><division><title>5.01Concurrent Interests</title>
<subdivision><title>[1]In General</title>
<arabicSubdivision><title>Arabic</title>
<section><title>section</title>
<paragraph>An owner.</paragraph><paragraph>On other</paragraph></section>
<section><title>sections</title>
<paragraph>entitled</paragraph><paragraph>in which</paragraph></section></arabicSubdivision></subdivision></division>
<division><title>division</title>
<section><title>section3</title>
<paragraph>entitled</paragraph><paragraph>demo</paragraph>
</section>
</division>
<section><title>sections4</title>
<paragraph>val demo</paragraph>
<paragraph>val which></paragraph>
</section>
</chapter>
有人可以帮助我使用XSLT获得预期的输出吗?因为我是XSLT的新手,做了一些工作但没有获得预期的输出。
我开发的XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()|@*" mode="pretrans">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
<xsl:template match="p[count(child::node())=0]" mode="pretrans"/>
<xsl:template match="doc">
<chapter-poc>
<xsl:apply-templates/>
</chapter-poc>
</xsl:template>
<xsl:template match="text">
<chapter>
<xsl:variable name="thr5pos" select="count(child::node()[@style='TRH7']/preceding-sibling::p)+1"/>
<xsl:apply-templates select="child::node()[position()<$thr5pos]" mode="presec"/>
<section>
<xsl:variable name="nodesets" >
<xsl:apply-templates select="child::node()[position()>=$thr5pos]" mode="pretrans"/>
</xsl:variable>
<xsl:apply-templates select="$nodesets" mode="postsec"/> <!---->
</section>
</chapter>
</xsl:template>
<xsl:template match="p" mode="presec">
<xsl:choose>
<xsl:when test="@style='TRH2'">
<title><xsl:apply-templates/></title>
</xsl:when>
<xsl:when test="@style='TRH4'">
<division>
<title><xsl:apply-templates/></title>
</division>
<xsl:choose>
<xsl:when test = "@style='TRH5'">
<subdivision>
<title><xsl:apply-templates/></title>
</subdivision>
</xsl:when>
<xsl:when test ="@style='TRH7'">
<section>
<title><xsl:apply-templates/></title>
</section>
</xsl:when>
<xsl:when test ="@style='TRH6'">
<arabicSubdivision>
<title><xsl:apply-templates/></title>
</arabicSubdivision>
</xsl:when>
<xsl:when test="@style='TRH7'">
<section>
<title><xsl:apply-templates/></title>
</section>
</xsl:when>
</xsl:choose>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="p" mode="postsec">
<xsl:variable name="thr5pos" select="count(preceding-sibling::p[@style='TRH7'][1]/preceding-sibling::p)+1"/>
<xsl:variable name="pos" select="count(preceding-sibling::p)+1"/>
<xsl:choose>
<xsl:when test="@style='TRH7'">
<title><xsl:apply-templates/></title>
</xsl:when>
<xsl:when test="count(child::node())=0"/>
<xsl:otherwise>
<paragraph>
<xsl:apply-templates/>
</paragraph>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="r">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="@id">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
我从XSLT获得的输出是
<chapter>
<title>Partial Interests</title>
<division>
<title>5.01Concurrent Interests</title>
</division>
<division>
<title>division</title>
</division>
<section>
<title>sections4</title>
<paragraph>val demo</paragraph>
<paragraph>val which</paragraph>
</section>
</chapter>
与预期输出不同。
推荐答案
以下是对for-each-group group-starting-with
使用递归分组的初始尝试(使用XSLT3):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
exclude-result-prefixes="#all"
xmlns:mf="http://example.com/mf"
expand-text="yes">
<xsl:param name="levels" as="map(xs:string, map(xs:string, xs:string))*"
select="map { 'TRH2' : map { 'container' : 'chapter', 'content' : 'title' } },
map { 'TRH4' : map { 'container' : 'division', 'content' : 'title' } },
map { 'TRH5' : map { 'container' : 'subdivision', 'content' : 'title' } },
map { 'TRH6' : map { 'container' : 'arabicSubdivision', 'content' : 'title' } },
map { 'TRH7' : map { 'container' : 'section', 'content' : 'title' } }"/>
<xsl:function name="mf:group" as="node()*">
<xsl:param name="elements" as="element(p)*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$elements" group-starting-with="p[@style = $levels[$level] => map:keys()]">
<xsl:choose>
<xsl:when test="self::p[@style = $levels[$level] => map:keys()]">
<xsl:element name="{$levels[$level]?*?container}">
<xsl:element name="{$levels[$level]?*?content}">
<xsl:value-of select="r"/>
</xsl:element>
<xsl:choose>
<xsl:when test="exists($levels[$level + 1])">
<xsl:sequence select="mf:group(tail(current-group()), $level + 1)"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="tail(current-group())"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="exists($levels[$level + 1])">
<xsl:sequence select="mf:group(current-group(), $level + 1)"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="text">
<xsl:sequence select="mf:group(*, 1)"/>
</xsl:template>
<xsl:template match="p[@style = 'TRNormal']">
<paragraphp>
<xsl:apply-templates select="r/node()"/>
</paragraphp>
</xsl:template>
<xsl:template match="p[not(has-children())]"/>
<xsl:output method="xml" indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
</xsl:stylesheet>
XSLT 3需要Saxon 9.8 HE或更高版本或Saxon-JS 2或Altova XML 2017 R3及更高版本。
但是,应该可以将levels
参数设置为某种XML数据结构,而不是轻量级的XPath 3.1映射,即
<xsl:param name="create-xml-levels">
<levels>
<xsl:iterate select="$levels">
<level key="{map:keys(.)}">
<container>{?*?container}</container>
<content>{?*?content}</content>
</level>
</xsl:iterate>
</levels>
</xsl:param>
会这样做并创建类似
的内容 <levels>
<level key="TRH2">
<container>chapter</container>
<content>title</content>
</level>
<level key="TRH4">
<container>division</container>
<content>title</content>
</level>
<level key="TRH5">
<container>subdivision</container>
<content>title</content>
</level>
<level key="TRH6">
<container>arabicSubdivision</container>
<content>title</content>
</level>
<level key="TRH7">
<container>section</container>
<content>title</content>
</level>
</levels>
您可以将其存储在使用doc
加载的辅助输入中,也可以存储为参数(如下所示):
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
exclude-result-prefixes="#all"
xmlns:mf="http://example.com/mf">
<xsl:param name="xml-levels-param">
<levels>
<level key="TRH2">
<container>chapter</container>
<content>title</content>
</level>
<level key="TRH4">
<container>division</container>
<content>title</content>
</level>
<level key="TRH5">
<container>subdivision</container>
<content>title</content>
</level>
<level key="TRH6">
<container>arabicSubdivision</container>
<content>title</content>
</level>
<level key="TRH7">
<container>section</container>
<content>title</content>
</level>
</levels>
</xsl:param>
<xsl:variable name="xml-levels" select="$xml-levels-param/levels/level"/>
<xsl:function name="mf:group-xml" as="node()*">
<xsl:param name="elements" as="element(p)*"/>
<xsl:param name="level" as="xs:integer"/>
<xsl:for-each-group select="$elements" group-starting-with="p[@style = $xml-levels[$level]/@key]">
<xsl:choose>
<xsl:when test="self::p[@style = $xml-levels[$level]/@key]">
<xsl:element name="{$xml-levels[$level]/container}">
<xsl:element name="{$xml-levels[$level]/content}">
<xsl:value-of select="r"/>
</xsl:element>
<xsl:choose>
<xsl:when test="exists($xml-levels[$level + 1])">
<xsl:sequence select="mf:group-xml(current-group()[position() gt 1], $level + 1)"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()[position() gt 1]"/>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="exists($xml-levels[$level + 1])">
<xsl:sequence select="mf:group-xml(current-group(), $level + 1)"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:function>
<xsl:template match="text">
<xsl:sequence select="mf:group-xml(*, 1)"/>
</xsl:template>
<xsl:template match="p[@style = 'TRNormal']">
<paragraphp>
<xsl:apply-templates select="r/node()"/>
</paragraphp>
</xsl:template>
<xsl:template match="p[not(node())]"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我只测试了在Saxon 10中仅使用XSLT 2功能尝试,因此您可以自己测试它是否可以与XSLT 2处理程序一起使用,它应该报告任何不存在的特性或函数的使用,但是使用XPath 2或XSLT 2替代应该很容易。
这篇关于无法使用分组执行XSLT转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文