我有以下XML:
<p:persons>
<p:surname>Surname1</p:surname>
<p:forename>Forename1</p:forname>
<p:surname>Surname2</p:surname>
</p:persons>
姓氏和名字节点都是可选的。我想将这个XML转换为HTML或纯文本,并显示如下内容:
-- Person1 --
surname: Surname1
forename: Forename1
-- Person2 --
surname: Surname2
forename: UNKNOWN
请注意,XML也可能看起来像因为forename和surname都是可选的:
<p:persons>
<p:forename>Forename1</p:surname>
<p:surname>Surname1</p:surname>
<p:forename>Forename2</p:forname>
</p:persons>
谢谢!
答案 0 :(得分:2)
虽然我认为此规范严重错误,但这里有一个代码片段可以满足您的需求:
<xsl:template name="writePersons">
<xsl:param name="list"/>
<xsl:param name="index" select="1"/>
<xsl:if test="count($list/p:forename[$index]|$list/p:surname[$index]) > 0">
<xsl:text>-- Person</xsl:text>
<xsl:value-of select="$index"/>
<xsl:text> --
surname: </xsl:text>
<xsl:choose>
<xsl:when test="$list/p:surname[$index]">
<xsl:value-of select="$list/p:surname[$index]"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>UNKNOWN</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>
forename: </xsl:text>
<xsl:choose>
<xsl:when test="$list/p:forename[$index]">
<xsl:value-of select="$list/p:forename[$index]"/>
</xsl:when>
<xsl:otherwise>
<xsl:text>UNKNOWN</xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:text>

</xsl:text>
<xsl:call-template name="writePersons">
<xsl:with-param name="index" select="$index + 1"/>
<xsl:with-param name="list" select="$list"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
答案 1 :(得分:0)
这是一个更简单的解决方案(没有明确的递归,没有xsl:choose
,xsl:otherwise
,xsl:call-template
,xsl:param
,xsl:with-param
):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:p="p">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pSurnameUnknown">surname: UNKNOWN</xsl:param>
<xsl:template match=
"p:surname
[not(preceding-sibling::*[1][self::p:forename])]">
--- Person<xsl:text/>
<xsl:number level="single" count=
"p:forename|p:surname[not(preceding-sibling::*[1]
[self::p:forename])]"/>
<xsl:text>---</xsl:text>
forename: UNKNOWN
surname: <xsl:value-of select="."/>
</xsl:template>
<xsl:template match="p:forename">
--- Person<xsl:text/>
<xsl:number level="single" count=
"p:forename|p:surname[not(preceding-sibling::*[1]
[self::p:forename])]"/>
<xsl:text>---</xsl:text>
forename: <xsl:value-of select="."/>
<xsl:if test="not(following-sibling::*[1][self::p:surname])">
<xsl:copy-of select="$pSurnameUnknown"/>
</xsl:if>
<xsl:apply-templates mode="second"
select="following-sibling::*[1][self::p:surname]"/>
</xsl:template>
<xsl:template match="p:surname" mode="second">
surname: <xsl:value-of select="."/>
</xsl:template>
<xsl:template match="p:surname"/>
</xsl:stylesheet>
应用于此XML文档(提供的文档格式正确):
<p:persons xmlns:p="p">
<p:surname>Surname1</p:surname>
<p:forename>Forename2</p:forename>
<p:surname>Surname2</p:surname>
</p:persons>
产生了想要的正确结果:
--- Person1---
forename: UNKNOWN
surname: Surname1
--- Person2---
forename: Forename2
surname: Surname2
<强>解释强>:
正确使用模板和模式匹配。
正确使用 <xsl:number>
答案 2 :(得分:0)
即使你已经接受了一个答案,我也会把我的帽子扔进戒指......因为到目前为止,我认为其他任何一种解决方案都不正确(尽管一个与给定的样本输出相匹配)。 / p>
这是我的实施:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0" xmlns:p="p">
<xsl:output method="text" />
<xsl:template match="/p:persons">
<xsl:apply-templates select="*[1]">
<xsl:with-param name="i" select="1" />
</xsl:apply-templates>
</xsl:template>
<!-- This template is applied to an element whenever it is
for a new person, i.e. when there is not a preceding
sibling element belonging to the same person. -->
<xsl:template match="p:forename | p:surname">
<xsl:param name="i"/>
<xsl:variable name="next" select="following-sibling::*[1]"/>
<xsl:variable name="surname" select="if (self::p:surname) then . else
if ($next[self::p:surname]) then $next else 'UNKNOWN'"/>
<xsl:variable name="forename" select="if (self::p:forename) then . else
if ($next[self::p:forename]) then $next else 'UNKNOWN'"/>
<xsl:value-of select="concat(if ($i > 1) then ' ' else '',
'--- Person', $i, '--- surname: ',
$surname, ' forename: ', $forename, ' ')"/>
<xsl:choose>
<xsl:when test="local-name($next) = local-name(.)">
<!-- Only one name is supplied. Start processing
the next sibling as a new person. -->
<xsl:apply-templates select="following-sibling::*[1]">
<xsl:with-param name="i" select="$i + 1"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise>
<!-- Both names are supplied. Skip the second name
and start processing the sibling after it.-->
<xsl:apply-templates select="following-sibling::*[2]">
<xsl:with-param name="i" select="$i + 1"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
我对不完整规范的解释是:从第一个forename / surname元素开始。如果前两个元素是forename和surname(按任意顺序),则对第一个人使用两个元素,并作为新人开始处理第三个元素。
否则,使用第一个元素并为未提供的名称提供“UNKNOWN”。然后开始处理下一个元素作为新人。
通过这个规范解释,我很确定没有某种递归就不可能正确实现,因为每个元素与前面或后面的关联可以取决于前一个元素如何关联(例如forename first?),这取决于之前的人,等等。
上面的第一个样本输入给出了所需的输出。 第二个(标签已更正)给出:
--- Person1---
surname: Surname1
forename: Forename1
--- Person2---
surname: UNKNOWN
forename: Forename2
更全面的例子:
<p:persons xmlns:p="p">
<p:surname>Surname1</p:surname>
<p:forename>Forename1</p:forename>
<p:surname>Surname2</p:surname>
<p:surname>Surname3</p:surname>
<p:surname>Surname4</p:surname>
<p:forename>Forename4</p:forename>
<p:forename>Forename5</p:forename>
<p:surname>Surname5</p:surname>
</p:persons>
给出
--- Person1---
surname: Surname1
forename: Forename1
--- Person2---
surname: Surname2
forename: UNKNOWN
--- Person3---
surname: Surname3
forename: UNKNOWN
--- Person4---
surname: Surname4
forename: Forename4
--- Person5---
surname: Surname5
forename: Forename5