如何跟踪从一个模板到另一个模板的位置?
How to keep track of position from a template to a different template?
我想在 svg 中表示以下 XML,但我目前在跟踪方面遇到问题
从 到 时的当前位置
在一个simplePath中,一个点之间的距离是50
从 simplePath 到 Jump,反之亦然,距离为 200
<root>
<simplePath>
<point>A</point>
<point>B</point>
<point>C</point>
</simplePath>
<jump>
<simplePath>
<point>D</point>
<point>E</point>
<point>F</point>
</simplePath>
</jump>
<simplePath>
<point>G</point>
</simplePath>
</root>
XML 的输出应该是:
A : 0
B : 50
C : 100
D : 300
E : 350
F : 400
G : 600
当它主要由 simplePath 组成时,我可以使用 ((position() -1) * 50)
我不知道如何使用
<xsl:template match="root">
<xsl:apply-templates select="simplePath | jump"/>
</xsl:template>
<xsl:template match="simplePath">
<xsl:apply-templates select="point"/>
</xsl:template>
<xsl:template match="point">
<xsl:value-of select="."/>
<xsl:value-of select="(position() - 1)* 50"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="jump">
<xsl:apply-templates select="simplePath"/>
</xsl:template>
输出:
A0
B50
C100
D0
E50
F100
G0
如果我正确理解要求,使用 XSLT 3(例如 Saxon 9.8 或更高版本、Saxon-JS 2、Altova XML 2017 R3 或更高版本)和一个累加器:
<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:accumulator name="distance" as="item()*" initial-value="0, ()">
<xsl:accumulator-rule match="point" select="if ($value[2] = 'point') then ($value[1] + 50, local-name()) else if ($value[2] = 'jump') then ($value[1] + 200, 'point') else ($value[1], local-name())"/>
<xsl:accumulator-rule match="jump" select="$value[1], local-name()"/>
<xsl:accumulator-rule match="jump" phase="end" select="$value[1], local-name()"/>
</xsl:accumulator>
<xsl:template match="point">
<xsl:comment>accumulator-before('distance') : {accumulator-before('distance')[1]}</xsl:comment>
<xsl:next-match/>
</xsl:template>
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:mode on-no-match="shallow-copy" use-accumulators="distance"/>
</xsl:stylesheet>
样本输出:
<root>
<simplePath><!--accumulator-before('distance') : 0-->
<point>A</point>
<!--accumulator-before('distance') : 50-->
<point>B</point>
<!--accumulator-before('distance') : 100-->
<point>C</point>
</simplePath>
<jump>
<simplePath><!--accumulator-before('distance') : 300-->
<point>D</point>
<!--accumulator-before('distance') : 350-->
<point>E</point>
<!--accumulator-before('distance') : 400-->
<point>F</point>
</simplePath>
</jump>
<simplePath><!--accumulator-before('distance') : 600-->
<point>G</point>
</simplePath>
</root>
这里有一个相对简单的查看方式:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="/root">
<xsl:call-template name="process">
<xsl:with-param name="points" select=".//point"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="process">
<xsl:param name="points" />
<xsl:param name="total" select="0"/>
<!-- output -->
<xsl:value-of select="$points[1]"/>
<xsl:text> : </xsl:text>
<xsl:value-of select="$total"/>
<!-- recursive call -->
<xsl:if test="count($points) > 1">
<xsl:text> </xsl:text>
<xsl:call-template name="process">
<xsl:with-param name="points" select="$points[position() > 1]"/>
<xsl:with-param name="total" select="if(boolean($points[1]/ancestor::jump) != boolean($points[2]/ancestor::jump)) then $total + 200 else $total + 50"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
应用于您的输入示例,这将 return:
结果
A : 0
B : 50
C : 100
D : 300
E : 350
F : 400
G : 600
我想在 svg 中表示以下 XML,但我目前在跟踪方面遇到问题
从
在一个simplePath中,一个点之间的距离是50
从 simplePath 到 Jump,反之亦然,距离为 200
<root>
<simplePath>
<point>A</point>
<point>B</point>
<point>C</point>
</simplePath>
<jump>
<simplePath>
<point>D</point>
<point>E</point>
<point>F</point>
</simplePath>
</jump>
<simplePath>
<point>G</point>
</simplePath>
</root>
XML 的输出应该是:
A : 0
B : 50
C : 100
D : 300
E : 350
F : 400
G : 600
当它主要由 simplePath 组成时,我可以使用 ((position() -1) * 50)
我不知道如何使用
<xsl:template match="root">
<xsl:apply-templates select="simplePath | jump"/>
</xsl:template>
<xsl:template match="simplePath">
<xsl:apply-templates select="point"/>
</xsl:template>
<xsl:template match="point">
<xsl:value-of select="."/>
<xsl:value-of select="(position() - 1)* 50"/>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="jump">
<xsl:apply-templates select="simplePath"/>
</xsl:template>
输出:
A0
B50
C100
D0
E50
F100
G0
如果我正确理解要求,使用 XSLT 3(例如 Saxon 9.8 或更高版本、Saxon-JS 2、Altova XML 2017 R3 或更高版本)和一个累加器:
<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:accumulator name="distance" as="item()*" initial-value="0, ()">
<xsl:accumulator-rule match="point" select="if ($value[2] = 'point') then ($value[1] + 50, local-name()) else if ($value[2] = 'jump') then ($value[1] + 200, 'point') else ($value[1], local-name())"/>
<xsl:accumulator-rule match="jump" select="$value[1], local-name()"/>
<xsl:accumulator-rule match="jump" phase="end" select="$value[1], local-name()"/>
</xsl:accumulator>
<xsl:template match="point">
<xsl:comment>accumulator-before('distance') : {accumulator-before('distance')[1]}</xsl:comment>
<xsl:next-match/>
</xsl:template>
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:mode on-no-match="shallow-copy" use-accumulators="distance"/>
</xsl:stylesheet>
样本输出:
<root>
<simplePath><!--accumulator-before('distance') : 0-->
<point>A</point>
<!--accumulator-before('distance') : 50-->
<point>B</point>
<!--accumulator-before('distance') : 100-->
<point>C</point>
</simplePath>
<jump>
<simplePath><!--accumulator-before('distance') : 300-->
<point>D</point>
<!--accumulator-before('distance') : 350-->
<point>E</point>
<!--accumulator-before('distance') : 400-->
<point>F</point>
</simplePath>
</jump>
<simplePath><!--accumulator-before('distance') : 600-->
<point>G</point>
</simplePath>
</root>
这里有一个相对简单的查看方式:
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8" />
<xsl:template match="/root">
<xsl:call-template name="process">
<xsl:with-param name="points" select=".//point"/>
</xsl:call-template>
</xsl:template>
<xsl:template name="process">
<xsl:param name="points" />
<xsl:param name="total" select="0"/>
<!-- output -->
<xsl:value-of select="$points[1]"/>
<xsl:text> : </xsl:text>
<xsl:value-of select="$total"/>
<!-- recursive call -->
<xsl:if test="count($points) > 1">
<xsl:text> </xsl:text>
<xsl:call-template name="process">
<xsl:with-param name="points" select="$points[position() > 1]"/>
<xsl:with-param name="total" select="if(boolean($points[1]/ancestor::jump) != boolean($points[2]/ancestor::jump)) then $total + 200 else $total + 50"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
应用于您的输入示例,这将 return:
结果
A : 0
B : 50
C : 100
D : 300
E : 350
F : 400
G : 600