XSL迭代平面XML结构

时间:2012-01-23 09:12:16

标签: xml xslt xpath

我有以下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>

谢谢!

3 个答案:

答案 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]) &gt; 0">
    <xsl:text>-- Person</xsl:text>
    <xsl:value-of select="$index"/>
    <xsl:text> --&#x0A;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>&#x0A;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>&#x0A;&#x0A;</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:choosexsl:otherwisexsl:call-templatexsl:paramxsl: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

<强>解释

  1. 正确使用模板和模式匹配。

  2. 正确使用 <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 '&#10;' else '',
         '--- Person', $i, '---&#10;surname: ',
         $surname, '&#10;forename: ', $forename, '&#10;')"/>

      <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