XSLT 2.0如何标记多个元素的值并将它们关联在一起以形成结果

时间:2014-02-06 13:04:03

标签: xml xslt xslt-2.0 tokenize

我刚刚开始研究XSLT。我的输入和预期输出如下,XSLT也在下面给出。我现在面临两个问题

  1. 正如您所看到的,我正在动态分配变量名称,并引发以下异常 net.sf.saxon.trans.XPathException: Required item type of the context item for the attribute axis is node(); supplied value has item type xs:string
  2. 当我将变量名称设置为某个静态字符串时,我没有收到异常,但是我没有看到预期的输出,即我想知道如何映射标记化的字符串
  3. 输入

    <students>
      <field name="id">1,2,3</field>
      <field name="name">a,b,c</field>
     </students>
    

    预期产出

    <students>
    <student>
        <id>1</id>
        <name>a</name>
    </student>
    <student>
        <id>2</id>
        <name>b</name>
    </student>
    <student>
        <id>3</id>
        <name>c</name>
    </student>
    </students>
    

    XSLT

    <xsl:stylesheet version="2.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:output indent="yes" method="xml"/>
    <xsl:strip-space elements="*"/>
    
    <xsl:template match="/" name="main">
    
        <xsl:for-each select="students/field">
            <xsl:for-each select="tokenize(.,',')">
                <xsl:element name="{@name}">
                    <xsl:value-of select="."/>
                </xsl:element>
            </xsl:for-each>
        </xsl:for-each>                     
    </xsl:template>
    </xsl:stylesheet>
    

2 个答案:

答案 0 :(得分:4)

我不确定为什么您展示的样式表使用XSLT 1.0,因为您使用XSLT 2.0标记了问题,而tokenize是2.0函数。

此外,您的预期输出包含我认为的拼写错误。也许这就是你的意思:

<student>
  <id>1</id>
  <name>a</name>
</student>
<student>
  <id>2</id>
  <name>b</name>
</student>

为什么会出现例外情况

在XSLT中,表达式在很大程度上依赖于上下文。如下所示的行:

<xsl:element name="{@name}">

取决于上下文,因为它检索当前模板匹配的name属性值或xsl:for-each中的当前项。

在您的情况下,上下文是这样的:

<xsl:for-each select="tokenize(.,',')">

因此,{@name}的上下文是一个标记化的字符串 - 当然没有任何属性。

<强>样式表

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

   <xsl:output indent="yes" method="xml"/>
   <xsl:strip-space elements="*"/>

   <xsl:template match="/students">
      <xsl:copy>
         <xsl:apply-templates/> 
      </xsl:copy>
   </xsl:template>

   <xsl:template match="field[@name='id']">
      <xsl:variable name="match" select="."/>
      <xsl:for-each select="tokenize(.,',')">
         <xsl:variable name="id-pos" select="position()"/>
         <student>
            <id>
               <xsl:value-of select="."/>
            </id>
            <name>
               <xsl:value-of select="tokenize($match/following-sibling::field[@name='name'],',')[position() = $id-pos]"/>
            </name>
         </student>
      </xsl:for-each>
   </xsl:template>

   <xsl:template match="text()"/>

</xsl:stylesheet>

<强>输出

<?xml version="1.0" encoding="UTF-8"?>
<students>
   <student>
      <id>1</id>
      <name>a</name>
   </student>
   <student>
      <id>2</id>
      <name>b</name>
   </student>
   <student>
      <id>3</id>
      <name>c</name>
   </student>
</students>

答案 1 :(得分:2)

假设您不知道field元素的数量和名称,则以下内容更通用(并避免多次标记值):

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

<xsl:output indent="yes"/>

<xsl:template match="students">
  <xsl:copy>
    <xsl:variable name="fields">
      <fields>
        <xsl:variable name="fields" select="field"/>
        <xsl:for-each select="field">
          <xsl:variable name="field" select="."/>
          <xsl:element name="{@name}s">
            <xsl:for-each select="tokenize(., ',')">
              <xsl:element name="{$field/@name}">
                <xsl:value-of select="."/>
              </xsl:element>
            </xsl:for-each>
          </xsl:element>
        </xsl:for-each>
      </fields>
    </xsl:variable>
    <xsl:for-each select="$fields/fields/*[1]/*">
      <xsl:variable name="pos" select="position()"/>
      <student>
        <xsl:copy-of select="$fields/fields/*/*[$pos]"/>
      </student>
    </xsl:for-each>
  </xsl:copy>
</xsl:template>

</xsl:stylesheet>