递归XML元素的XSLT



我正在研究游泳程序的XML标准。我创建了一个XML模式和一些示例XML文件。由于游泳程序经常使用重复(例如4 x 100米自由泳),所以我创建了一个XML元素<instruction>,它可以包含更多的自身实例。它使用<XS:choice>来包括<repetition>(例如4 x)或直接游泳指导(100米自由泳)。<repetition>然后可以包括进一步的重复和/或直接游泳指导。下面是一个示例XML文件:

<?xml version="1.0" encoding="UTF-8"?>
<program xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="file:/Users/cba56/Dropbox%20(UC%20Enterprise)/swimML/oxygen/swiML.xsd">
<!-- Complex program with repetitions and loops -->
<title>Complex Program</title>
<author>
<firstName>Christoph</firstName>
<lastName>Bartneck</lastName>
<email>christoph@bartneck.de</email>
</author>
<author>
<firstName>Matthias</firstName>
<lastName>MccCurdy</lastName>
<email>mc@swim.com</email>
</author>
<creationDate>2022-06-30</creationDate>
<poolLength>25</poolLength>
<poolLengthUnit>meters</poolLengthUnit>
<defaultInstructionLengthUnit>meters</defaultInstructionLengthUnit>
<!-- Examples of a veriety of instructions -->
<instruction>
<lengthAsDistance>100</lengthAsDistance>
<rest><afterStop>PT20S</afterStop></rest>
<intensity><staticIntensity>
<precentageEffort>70</precentageEffort>
</staticIntensity></intensity>
<stroke><standardStroke>freestyle</standardStroke></stroke>
<equipment>pads</equipment>
<equipment>pullBuoy</equipment>
</instruction>
<instruction>
<lengthAsDistance>100</lengthAsDistance>
<rest><sinceStart>PT1M45S</sinceStart></rest>
<intensity><staticIntensity>
<precentageEffort>70</precentageEffort>
</staticIntensity></intensity>
<stroke><kicking>
<orientation>front</orientation>
<legMovement>flutter</legMovement>
</kicking></stroke>
</instruction>
<instruction>
<lengthAsDistance>400</lengthAsDistance>
<rest><inOut>3</inOut></rest>
<intensity>
<startIntensity>
<precentageEffort>60</precentageEffort>
</startIntensity>
<stopIntensity>
<precentageEffort>100</precentageEffort>
</stopIntensity>
</intensity>
<stroke><standardStroke>freestyle</standardStroke></stroke>
</instruction>
<!-- An example of a simple repetition -->
<!-- It uses IM as the repetition stroke, so 100FL, 100BK, 100BR, 100FR -->
<instruction>
<repetition>
<repetitionCount>4</repetitionCount>
<stroke><standardStroke>individualMedley</standardStroke></stroke>
<instruction>
<lengthAsDistance>100</lengthAsDistance>
<rest><sinceStart>PT1M45S</sinceStart></rest>
<intensity><staticIntensity>
<zone>tempo</zone>
</staticIntensity></intensity>
</instruction>
</repetition>
</instruction>
<!-- Example of a repeition changing intensity.  -->
<!-- This would be a build exercise -->
<instruction>
<repetition>
<repetitionCount>4</repetitionCount>
<intensity>
<startIntensity>
<precentageEffort>60</precentageEffort>
</startIntensity>
<stopIntensity>
<precentageEffort>100</precentageEffort>
</stopIntensity>
</intensity>
<instruction>
<lengthAsDistance>100</lengthAsDistance>
<stroke><standardStroke>freestyle</standardStroke></stroke>
<breath>5</breath>
</instruction>
</repetition>
</instruction>
<!-- Exmaple of a repeition inside a repetition -->
<instruction>
<repetition>
<repetitionCount>4</repetitionCount>
<instruction>
<repetition>
<repetitionCount>2</repetitionCount>
<instruction>
<lengthAsDistance>50</lengthAsDistance>
<stroke><standardStroke>backstroke</standardStroke></stroke>
</instruction>
<instruction>
<lengthAsDistance>50</lengthAsDistance>
<stroke><standardStroke>breaststroke</standardStroke></stroke>
</instruction>
</repetition>
</instruction>
<instruction>
<lengthAsDistance>200</lengthAsDistance>
<stroke><standardStroke>freestyle</standardStroke></stroke>
</instruction>
</repetition>
</instruction>
<!-- some basic instructions -->
<instruction>
<lengthAsTime>PT2M30S</lengthAsTime>
<lenghUnit>time</lenghUnit>
<stroke><standardStroke>freestyle</standardStroke></stroke>
</instruction>
<instruction>
<lengthAsTime>PT1M30S</lengthAsTime>
<stroke><standardStroke>freestyle</standardStroke></stroke>
</instruction>
<instruction>
<lengthAsDistance>8</lengthAsDistance>
<lenghUnit>laps</lenghUnit>
<intensity><staticIntensity>
<zone>endurance</zone>
</staticIntensity></intensity>
<stroke><standardStroke>backstroke</standardStroke></stroke>
</instruction>
</program>

我现在尝试使用XSLT将instance1.xml转换为类似于goal.xhtml的内容。下面是目标。xhtml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Complex Program</title>
</head>
<body>
<h1>Complex Program</h1>
<h2>Description:</h2>
<p></p>
<p>Target Pool Length: 25 meters</p>
<p>Default Length Unit: meters</p>
<p>Creation Date: 30 June 2022</p>
<h2>Authors:</h2>
<ul>
<li>Christoph Bartneck, christoph@bartneck.de</li>
<li>Matthias MccCurdy, </li>
</ul>
<h2>Program:</h2>
<ul>
<li>100 FR w20 70% Pads and Pullboy</li>
<li>100 Kick Front Flutter @1:45 70%</li>
<li>400 FR 3nd in 1st out 60%</li>
<li>4x IM <ul>
<li>100 @1:45 Tempo</li>
</ul>
</li>
<li>4x build 60%-100% <ul>
<li>100 FR b5</li>
</ul>
</li>
<li>4x <ul>
<li>2x <ul>
<li>50 BK</li>
<li>50 BR</li>
</ul>
</li>
<li>200 FR</li>
</ul>
</li>
<li>2:30 FR</li>
<li>8L BK Endurance</li>
</ul>
</body>
</html>

虽然我能够进行基本的XSLT转换(例如<author>),但我正在与XML模式和<instruction>'元素的递归性质作斗争。我就是不知道怎么从解决方案开始。

有没有人可以看一下XML文件的例子,并建议XSLT转换的策略?

XSLT中处理递归XML结构(即可以包含其他相同类型元素的元素)的一般策略是使用模板匹配。您将创建一个与相关元素匹配的模板(例如<xsl:template match="instruction">);然后,模板生成一些输出,并使用xsl:apply-templates处理子元素,这(假设有相同类型的子元素)实际上是对同一模板的递归调用。

强化@ConalTuohy的回答,XSLT样式表的标准设计模式处理递归甚至不需要考虑它。问你自己"当我遇到instruction元素时我需要做什么",答案可能是"生成一个ul元素,它的子元素包含li元素"。写一个模板规则,比如

<xsl:template match="instruction">
<ul>
<xsl:for-each select"child::node()">
<li><xsl:apply-templates select="."/></li.
</xsl:for-each>
</ul>
</xsl:template>

注意:这个答案与"我如何开始"的一般问题有关。我还没有详细研究你的投入和产出。

算出来了。这应该可以解决这个问题:

<xsl:template match="instruction">
<xsl:apply-templates select="repetition"/>
<xsl:apply-templates select="lengthAsDistance"/>
<xsl:apply-templates select="lengthAsTime" />
</xsl:template>
<xsl:template match="repetition">
<li>Repetition Count: <xsl:value-of select="repetitionCount"/></li>
<ol>
<xsl:apply-templates select="instruction"/>
</ol>
</xsl:template>