我想将包含在(嵌套)列表中的列表标题的TEI / xml文档转换为html。因此,当我遇到其中一个标题时,我需要在转换实际标题之前启动列表处理。
My(xslt-2.0)样式表忽略head[(parent::list)]
元素,而是在匹配“list”的模板中处理这些情况:这会创建一些环境('section'),如果列表中有一个“head”子元素,它将head [(parent :: list)]的匹配模板以非默认模式应用于head子项,然后通过将ul
/ ol
与项目放在一起。但是这会导致以下错误消息:
A sequence of more than one item is not allowed as the value in 'cast as' expression
我不能简单地使用<xsl:value-of select="child::head">
(这不会导致错误),因为标题可以包含我需要呈现的其他元素,例如分页元素。
以下是示例文档的摘录:
<div>
<list>
<head>
<pb facs="facs:W0013-0005" n="[2]"/>
<lb n="1"/>PRIMUS TOMUS,
</head>
<item>
<lb n="2"/>De
<list>
<item><lb n="3"/>Potestate ecclesiae, prior et posterior.</item>
<item><lb n="4"/>Potestate civili.</item>
</list>
</item>
</list>
</div>
这是我的样式表:
的摘要<!-- In a first approach, ignore headings when they are inside a list -->
<xsl:template match="head[(parent::list)]" />
<!-- Here is what should be done with them, but this needs to be called somewhere -->
<xsl:template match="head[(parent::list)]" mode="listIsDone">
<h4>
<!-- this works, but is not what i need: <xsl:value-of select="."/> -->
<xsl:apply-templates />
</h4>
</xsl:template>
<!-- Here is how headings (outside of lists) are handled -->
<xsl:template match="head[not(parent::list)]">
<h3>
<xsl:apply-templates/>
</h3>
</xsl:template>
<!-- Here is how lists are handled -->
<xsl:template match="list">
<xsl:choose>
<!-- When the list contains a heading, then transform it according
to the headings-inside-of-lists template -->
<xsl:when test="child::head">
<section>
<xsl:for-each select="child::head">
<xsl:apply-templates select="." mode="listIsDone"/>
</xsl:for-each>
<!-- Then add an unordered list for the list "contents"/items -->
<ul>
<xsl:apply-templates/>
</ul>
</section>
</xsl:when>
<!-- If the list does not contain a heading, add only the unordered list -->
<xsl:otherwise>
<ul>
<xsl:apply-templates/>
</ul>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
这是我想要的 html :
<section>
<h4><!-- Here begins output of the p-matching template --> | <div class="pageNumbers">
<a class="pageNo" href="someURL-gotten-from-the-facs-attribute">11</a>
</div><!-- Here ends output of the p-matching template -->
PRIMUS TOMUS,
</h4>
<ul>
<li> De
<ul>
<li>Potestate ecclesiae, prior et posterior.</li>
<li>Potestate civili.</li>
</ul>
</li>
</ul>
</section>
我希望这足以说明我想要实现的目标以及我遇到的问题。 <xsl:apply-templates select="." mode="listIsDone"/>
不应该做我想做的事吗?
我无法找到任何搜索/谷歌搜索错误消息,这些错误信息与“空序列”,“铸造为'表达式”中的值或我未使用的xsl函数有关(在此处)。
我刚刚尝试了第二种方法,call-template
也没有产生正确的结果:
样式表:
<xsl:template name="list-heading">
<xsl:param name="heading-node"/>
<h4>
<xsl:apply-templates select="$heading-node" mode="listIsDone"/>
</h4>
</xsl:template>
...
<!-- and the in the matching template for "list", just like above, only at the for-each it is: -->
<xsl:for-each select="child::head">
<xsl:call-template name="list-heading">
<xsl:with-param name="heading-node">
<xsl:copy-of select="."/>
</xsl:with-param>
</xsl:call-template>
</xsl:for-each>
这不会呈现标题的其他子元素(特别是<pb>
)......
FWIW,我想在eXist中做这一切,我认为内部以某种方式使用Saxon。但是不要问我这些内部实现的细节,当我试图找到它们时,我对它的理解不够。 感谢您提供任何帮助
答案 0 :(得分:1)
我不确定这是请求的输出还是可以在您的设置中使用,但只是想分享以下方法:
<?xml version="1.0"?><xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html"/>
<xsl:template match="/*">
<html>
<head></head>
<body>
<xsl:apply-templates select="list[not(child::list)]"/>
</body>
</html>
</xsl:template>
<xsl:template match="list[not(child::list)]">
<section>
<xsl:choose>
<xsl:when test="child::head">
<xsl:apply-templates select="child::head"/>
</xsl:when>
<xsl:otherwise>
<h3>
<xsl:text>No header for this list</xsl:text>
</h3>
</xsl:otherwise>
</xsl:choose>
<ul>
<xsl:apply-templates select="child::item/list" mode="list"/>
</ul>
</section>
</xsl:template>
<xsl:template match="head" >
<h4>
<xsl:apply-templates mode="header"/>
</h4>
</xsl:template>
<xsl:template match="pb" mode="header"/>
<xsl:template match="lb" mode="header"/>
<xsl:template match="list" mode="list">
<xsl:for-each select="./item">
<xsl:apply-templates select="." mode="list"/>
</xsl:for-each>
</xsl:template>
<xsl:template match="item" mode="list">
<li>
<xsl:apply-templates mode="listItem"/>
</li>
</xsl:template>
<xsl:template match="item" mode="listItem"/>
</xsl:stylesheet>
为了进行测试,我刚刚在没有标题的XML示例中添加了第二个列表:
<list>
<item>
<lb n="2"/>De
<list>
<item><lb n="3"/>Potestate ecclesiae, prior et posterior.</item>
<item><lb n="4"/>Potestate civili.</item>
</list>
</item>
</list>
结果:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<section>
<h4>
PRIMUS TOMUS,
</h4>
<ul>
<li>Potestate ecclesiae, prior et posterior.</li>
<li>Potestate civili.</li>
</ul>
</section>
<section>
<h3>No header for this list</h3>
<ul>
<li>Potestate ecclesiae, prior et posterior.</li>
<li>Potestate civili.</li>
</ul>
</section>
</body>
</html>
由于我不知道在标题丢失的情况下应该是什么标题,我只是添加了一些默认副本;由于我不知道您希望如何处理<pb>
和<lb>
,因此他们只是匹配一个可以针对所需输出进行调整的空模板。
更新:在OP中添加所需的HTML输出之前发布了上述方法。我会稍后调整它以符合要求,因为我现在正在工作。建议解决方案的一个主要区别就是从每个外部列表条目开始,并从上到下处理缺少的标题,而不是从内部列表开始并从那里检查标题。由于在第一个模板match="list[not(child::list)]"
中提供了生成单独部分输出所需的所有条目,我认为从那里开始更容易。
更新2:调整后的模板以匹配所需的输出,但仍有一些问题。
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html"/>
<xsl:template match="/*">
<html>
<head></head>
<body>
<xsl:apply-templates select="list[not(child::list)]"/>
</body>
</html>
</xsl:template>
<xsl:template match="list[not(child::list)]">
<section>
<xsl:choose>
<xsl:when test="child::head">
<xsl:apply-templates select="child::head"/>
</xsl:when>
<xsl:otherwise>
<h3>
<xsl:text>No header for this list</xsl:text>
</h3>
</xsl:otherwise>
</xsl:choose>
<ul>
<li>
<xsl:apply-templates select="child::item" mode="listItem"/>
<xsl:apply-templates select="child::item/list" mode="list"/>
</li>
</ul>
</section>
</xsl:template>
<xsl:template match="head" >
<h4>
<xsl:apply-templates mode="header"/>
</h4>
</xsl:template>
<xsl:template match="pb" mode="header">
<xsl:variable name="facs" select="./@facs"/>
<xsl:variable name="pageNo" select="./@n"/>
<xsl:variable name="pageNoResolved" select="translate($pageNo, '[]', '')"/>
<!-- tbd: get href from facs with additional function -->
<!-- tbd: get pageNo from pageNo with additional function -->
<div class="pageNumbers">
<a class="pageNo">
<xsl:attribute name="href" select="$facs"/>
<xsl:value-of select="$pageNoResolved"/>
</a>
</div>
</xsl:template>
<xsl:template match="lb" mode="header"/>
<xsl:template match="list" mode="list">
<ul>
<xsl:for-each select="./item">
<xsl:apply-templates select="." mode="list"/>
</xsl:for-each>
</ul>
</xsl:template>
<xsl:template match="item" mode="list">
<li>
<xsl:apply-templates mode="listItem"/>
</li>
</xsl:template>
<xsl:template match="item" mode="listItem">
<xsl:apply-templates mode="cleaning"/>
</xsl:template>
<xsl:template match="lb" mode="cleaning"/>
<xsl:template match="item" mode="cleaning"/>
</xsl:stylesheet>
HTML输出:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<section>
<h4>
<div class="pageNumbers">
<a class="pageNo" href="facs:W0013-0005">2</a>
</div>
PRIMUS TOMUS,
</h4>
<ul>
<li>
De
<ul>
<li>Potestate ecclesiae, prior et posterior.</li>
<li>Potestate civili.</li>
</ul>
</li>
</ul>
</section>
</body>
</html>
剩下的问题是:是否总会有&#34; | &#34;在<h4>
和<div>
之间?由于我不知道这是否可以改变,我只是将其添加为静态文本。因为我不知道如何检索href和pagenumber - 正如你提到的href将从facs
- 属性中检索 - 我只是添加了值。如果pagenumber只是n="[2]"
- pb
属性的值,我只是删除了括号。
答案 1 :(得分:0)
事实证明最初的方法是正确的。
错误是在某个函数中生成的,该函数在该过程的后期很晚才在模板中调用。因此,当我使用apply-templates处理列表标题时触发了它,并且当我使用value-of或切换模式而没有调整所有其他匹配模板再次启动时时触发它。
错误(由xs:string($nodeA@xml:id)
实际上是几个节点时使用nodeA
导致)导致修复后,我可以使用此样式表来实现我想要的内容:
<xsl:template match="head[not(parent::list)]">
<h3>
<xsl:apply-templates/>
</h3>
</xsl:template>
<xsl:template match="list">
<section>
<xsl:for-each select="child::head">
<h4>
<xsl:apply-templates />
</h4>
</xsl:for-each>
<xsl:for-each select="node()[not(local-name()='head')]">
<ul>
<xsl:apply-templates />
</ul>
</xsl:for-each>
</section>
</xsl:template>
如果我没有忽略某些东西,这是一种更好的方法,因为它根本不使用模式(复杂性较低),不需要重复定义模板(列表的内部和外部),并且是关于级别的通用嵌套列表。
当然,完全错误地猜到了发生实际错误的地方,从而向错误的方向提出要求,这是非常尴尬的。 (好吧,至少我确实提到了错误信息,但是在我发布的样式表片段之外,显然没有帮助我或其他任何人发现错误。)
所以我真诚地道歉,因为事实上问题就在其他地方,所以你会花费这么多的努力。