2012-07-15 114 views
1

我熟悉XSLT的基础知识,但是我遇到了一个奇怪的情况,我似乎无法弄清楚。我很抱歉这么久,但我会很感激你能提供的任何帮助。使用XSLT添加属性,然后使用该新属性进行排序

我对由我无法控制的软件产品生成的XML进行转换。产品导出如下所示的数据:

<header> 
    <data> 
    </data> 
</header> 
<transaction> 
    <B1_PG1 ts='1139977698718.75'><data></data></B1_PG1> 
    <B1_PG2 ts='1139977698718.76'><data></data></B1_PG2> 
    <B2_PG1 ts='1139977698718.77'><data></data></B2_PG1> 
    <B2_PG2 ts='1139977698718.78'><data></data></B2_PG2> 
    <B2_PG1 ts='1139977698718.79'><data></data></B2_PG1> 
    <B2_PG2 ts='1139977698718.80'><data></data></B2_PG2> 
    <B3_PG1 ts='1139977698718.81'><data></data></B3_PG1> 
</transaction> 

其中软件产品按照接收它们的顺序导出数据页面。我需要将这些页面按自定义顺序排序,以便处理到另一个系统中。所以,我创建了一个查找的文件,看起来像这样来定义我的自定义排序顺序:

(PageSequences.xml)

<pages> 
    <page id="B2_PG1" sequence="1000" /> 
    <page id="B2_PG2" sequence="1010" /> 
    <page id="B3_PG1" sequence="2000" /> 
    <page id="B1_PG1" sequence="3000" /> 
    <page id="B1_PG2" sequence="3010" /> 
</pages> 

我再根据元素名称查找该序列,串联,与时间戳,并使用以下XSLT注入的属性到元素:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 
    <xsl:variable name='page-seqs' select='document("PageSequences.xml")/pages/page'/> 

    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="transaction"> 
     <transaction> 

      <xsl:for-each select="child::node()"> 
       <xsl:variable name='localname' select='local-name()'/> 
       <xsl:copy> 
        <xsl:attribute name="sequence"> 
         <xsl:value-of select='$page-seqs[@id=$localname]/@sequence'/>-<xsl:value-of select='@ts'/> 
        </xsl:attribute> 
        <xsl:apply-templates select="@*|node()"> 
         <xsl:sort select="@sequence" /> 
        </xsl:apply-templates> 
       </xsl:copy> 
      </xsl:for-each> 
     </transaction> 
     </xsl:template> 

</xsl:stylesheet> 

我遇到的问题是,标签似乎并不奏效。我希望以下内容:

<transaction> 
    <B2_PG1 ts='1139977698718.77' sequence='1000-1139977698718.77'><data></data></B2_PG1> 
    <B2_PG1 ts='1139977698718.79' sequence='1000-1139977698718.79'><data></data></B2_PG1> 
    <B2_PG2 ts='1139977698718.78' sequence='1010-1139977698718.78'><data></data></B2_PG2> 
    <B2_PG2 ts='1139977698718.80' sequence='1010-1139977698718.80'><data></data></B2_PG2> 
    <B3_PG1 ts='1139977698718.81' sequence='2000-1139977698718.81'><data></data></B3_PG1> 
    <B1_PG1 ts='1139977698718.75' sequence='3000-1139977698718.75'><data></data></B1_PG1> 
    <B1_PG2 ts='1139977698718.76' sequence='3010-1139977698718.76'><data></data></B1_PG2> 
</transaction> 

,但我发现:

<transaction> 
    <B1_PG1 ts='1139977698718.75' sequence='3000-1139977698718.75'><data></data></B1_PG1> 
    <B1_PG2 ts='1139977698718.76' sequence='3010-1139977698718.76'><data></data></B1_PG2> 
    <B2_PG1 ts='1139977698718.77' sequence='1000-1139977698718.77'><data></data></B2_PG1> 
    <B2_PG2 ts='1139977698718.78' sequence='1010-1139977698718.78'><data></data></B2_PG2> 
    <B2_PG1 ts='1139977698718.79' sequence='1000-1139977698718.79'><data></data></B2_PG1> 
    <B2_PG2 ts='1139977698718.80' sequence='1010-1139977698718.80'><data></data></B2_PG2> 
    <B3_PG1 ts='1139977698718.81' sequence='2000-1139977698718.81'><data></data></B3_PG1> 
</transaction> 

另外,请让我知道,如果你认为我在错误的方式接近这一点。我试图避免使用java/c#/ perl/etc ...来保持转换尽可能便携。出于性能原因,我也想避免执行两次转换。谢谢!

回答

0

你的问题是代码

<xsl:copy> 
    <xsl:attribute name="sequence"> 
     <xsl:value-of select='$page-seqs[@id=$localname]/@sequence'/>-<xsl:value-of select='@ts'/> 
    </xsl:attribute> 
    <xsl:apply-templates select="@*|node()"> 
     <xsl:sort select="@sequence" /> 
    </xsl:apply-templates> 
</xsl:copy> 

尤其是应用模板该块内。首先,在此阶段,您已经复制并输出“B-PG”元素,并且所有应用模板正在处理其子节点。其次,排序只适用于输入文档,而不是任何额外的属性添加到输出文档。

然后你可以做什么,把你把事务子节点复制到一个变量中的结果,然后用一个排序遍历该变量。这将是同一个XSLT文档中的“双向转换”。但是,在这种情况下,这是没有必要的。您只需简单地匹配所有事务子节点,并在排序

<xsl:sort select="$page-seqs[@id=local-name(current())]/@sequence" /> 

这里指定序列号的查询是完整的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:variable name="page-seqs" select="document('C:\lookup.xml')/pages/page"/> 

    <xsl:template match="node()|@*"> 
     <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="transaction"> 
     <transaction> 
     <xsl:apply-templates select="child::node()"> 
      <xsl:sort select="$page-seqs[@id=local-name(current())]/@sequence"/> 
     </xsl:apply-templates> 
     </transaction> 
    </xsl:template> 
</xsl:stylesheet> 

当适用于您的样本文件(减去元件,因为目前的XML样品没有很好地形成),下面是输出

<transaction> 
    <B2_PG1 ts="1139977698718.77"> 
     <data/> 
    </B2_PG1> 
    <B2_PG1 ts="1139977698718.79"> 
     <data/> 
    </B2_PG1> 
    <B2_PG2 ts="1139977698718.78"> 
     <data/> 
    </B2_PG2> 
    <B2_PG2 ts="1139977698718.80"> 
     <data/> 
    </B2_PG2> 
    <B3_PG1 ts="1139977698718.81"> 
     <data/> 
    </B3_PG1> 
    <B1_PG1 ts="1139977698718.75"> 
     <data/> 
    </B1_PG1> 
    <B1_PG2 ts="1139977698718.76"> 
     <data/> 
    </B1_PG2> 
</transaction> 

待办事项吨最好使用apply-templates来替换每一个,这就是我在这里所做的。

+0

这是完美的蒂姆,非常感谢。它允许我执行排序而不需要添加属性所需的传递。它将允许对任何元素进行自定义排序。 – 2012-07-16 02:13:26

1

您创建的属性存在于要放置在结果树中的新构建的元素上,但它不存在于要排序的源树中的元素上。

另一个问题是,你没有排序交易元素的孩子,但它的孙子。

我怀疑你想要的东西是这样的:

  <xsl:for-each select="child::node()"> 
       <xsl:sort select="concat($page-seqs[@id=local-name(current())]/@sequence, '-', @ts)"/> 
       <xsl:variable name='localname' select='local-name()'/> 
       <xsl:copy> 
        <xsl:attribute name="sequence"> 
         <xsl:value-of select='$page-seqs[@id=$localname]/@sequence'/>-<xsl:value-of select='@ts'/> 
        </xsl:attribute> 
        <xsl:apply-templates select="@*|node()"/> 
       </xsl:copy> 
      </xsl:for-each> 

,以避免重复计算(一旦在xsl:排序,一旦产生输出属性)的唯一方法是做两遍,一个添加属性,下一个排序。这种做法的方式在XSLT 1.0和2.0之间有所不同,并且您没有说明您正在使用哪种方法。两种方法是相当可行的,但在你的情况下,我怀疑重复计算的单次传球效率更高(尽管你必须测量两者以找出答案)。

+0

迈克尔,我很欣赏你试图让我的平均XSLT理念工作不足,这也可以做到。 – 2012-07-16 02:15:05