如何使用XSLT 2在XSD xshema文件中给出的序列对元素进行排序:perform-sort

时间:2013-12-17 08:54:17

标签: xslt xslt-2.0

我正在使用SaxonHE jar用于XSLT 2.0处理器,以通过XSD将元素的顺序更改为所需的序列。但没有得到理想的输出 我的xml文件是:

<param xsi:type="Bank">  
     <bankData name="ABC"/>  
     <branchAddress id="ABCB1">NY</branchAddress>  
     <legalAddress id="ABCL1">UK</legalAddress>  
</param>    

根据XSD,param标签的子元素的正确顺序是bankData,legalAddress,branchAddress。 标签参数可以包含任何类型的数据。因此,如果属性类型为“Bank”

,则应更改序列

我正在使用此XSL代码来更改序列:

<xsl:variable name="bankElementSeq" as="element()*">  
    <bankData/><legalAddress/><branchAddress/>  
</xsl:variable>  
<xsl:template match="param/*">  
   <xsl:if test="param/@xsi:type='Bank'">  
       <xsl:perform-sort select="param/*">  
           <xsl:sort select="index-of($bankElementSeq//node-name(.), node-name(.))"/>  
       </xsl:perform-sort>  
   </xsl:if>  
</xsl:template>  

必需的输出是:

<param xsi:type="Bank">  
   <bankData name="ABC"/>  
   <legalAddress id="ABCL1">UK</legalAddress>  
   <branchAddress id="ABCB1">NY</branchAddress>  
</param>    

但我得到的输出为:

<param xsi:type="Bank">  
</param>    

未写入子元素 这可能是什么问题?

2 个答案:

答案 0 :(得分:0)

请参阅@ MichaelKay的解决方案,以便很好地解释为什么您当前的方法不起作用。

我想建议一种略微不同的方法。它不会尝试对条目进行排序,而只是使用辅助变量来迭代而不是param中的子标记。这应该在功能上等同于现在,但是在其他设置中可能有一些优势,在这些设置中您只想输出标签的子集。您只需在辅助变量中包含所需的标记,并将所有其他标记保留在其中。

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />

  <xsl:variable name="bankElementSeq" as="element()*">  
    <bankData/><legalAddress/><branchAddress/>  
  </xsl:variable>

  <!-- the following pattern restricts the match to exactly the type of param you want to modify -->
  <xsl:template match="param[@xsi:type='Bank']">  

    <xsl:copy>     
      <xsl:copy-of select="@*"/>
      <xsl:variable name="param" select="."/>

      <!-- iterate over the elements in the sorting order -->
      <xsl:for-each select="$bankElementSeq">        
        <!-- and copy the found found by 'local-name' -->
        <xsl:copy-of select="$param/*[local-name() = local-name(current())]"/>
      </xsl:for-each>

    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:0)

让我们更详细地看一下这段代码:

<xsl:template match="param/*">  
   <xsl:if test="param/@xsi:type='Bank'">  
       <xsl:perform-sort select="param/*">  
           <xsl:sort select="index-of($bankElementSeq//node-name(.), node-name(.))"/>  
       </xsl:perform-sort>  
   </xsl:if>  
</xsl:template>

首先,此模板依次应用于param 的每个子项。它会影响所选元素的处理方式,不会影响处理所选元素的时间。要重新排列“param”的子元素,您需要模板中的“param”元素逻辑,而不是其子元素的模板。

其次,在模板中,您有一个相对路径表达式param / @ xsi:type。这是相对于上下文节点评估的,上下文节点是“param”的子节点。所以你正在寻找一个自称为param的param的孙子。您的示例XML没有这样的孙子。你在xsl的路径表达式中重复这个错误:perform-sort / @ select。

所以你实际上可以实现你想要的东西:

<xsl:template match="param[@xsi:type='Bank']">  
   <xsl:perform-sort select="*">  
      <xsl:sort select="index-of($bankElementSeq/node-name(.), node-name(.))"/>  
   </xsl:perform-sort>    
</xsl:template>