10

开始是一件简单的事情,但对于 XSLT 菜鸟来说却相当麻烦。

尝试对子节点/降序进行排序,但是在向其父节点添加属性后,在 VS2010 中调试时收到错误消息:

"Attribute and namespace nodes cannot be added to the parent element after a text, comment, pi, or sub-element node has already been added."

假设我有这个简单的 XML:

<posts>
    <year value="2013">
        <post postid="10030" postmonth="1">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
        <post postid="10040" postmonth="2">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
        <post postid="10050" postmonth="3">
             <othernode></othernode>
             <othernode2></othernode2>
        </post>
    </year>
    <year value="2012">
        <post postid="10010" postmonth="1">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
        <post postid="10015" postmonth="2">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
        <post postid="10020" postmonth="3">
             <othernode></othernode>
             <othernode2></othernode2>
        </post>
    </year>
</posts>

我将 XPATH 传递给 xmldatasource 以检索相关<year>节点,例如 2013。然后我需要<post>使用 postid 对其子节点进行降序排序,因此对于<year value=2013>, postid=10050 将在呈现时首先显示。

所以,要明确一点:我只对在一个<year>节点内进行排序感兴趣。

在我将节点拆分为单独的节点(即 xml 是 /posts/post)之前,以下 XSLT 工作:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()">
                <xsl:sort select="@postid" data-type="text" order="descending"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

由于上述错误,现在运行时 xmldatasource 为空。如果我按升序传递,则明显返回相同的 xml(无转换)

问题:如何更新上述(或新的)XSLT 以适应父节点属性(<year value="">)?通过研究,一个答案说“我需要在创建元素之前添加属性创建”。这是有道理的,因为观察调试器,子节点是按 desc 顺序形成的,但是 year 标签缺少它的属性。但是我对 XSLT 真的一无所知。看不出它太复杂,但就是不懂语言。

任何帮助,非常感谢。谢谢

4

2 回答 2

11

那么您是说您只是将部分 XML 文档(一个<year>节点)传递给 XSLT 处理器吗?

您应该为年份使用单独的模板,以便这是唯一使用排序的模板。以下情况如何:

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

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

  <xsl:template match="year">
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates select="post">
        <xsl:sort select="@postid" data-type="number" order="descending"/>
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

我认为上面是一个更好的方法,但我认为你的错误的根本原因是它在进行排序时将属性与元素混合在一起。如果您只是这样做,您的原始 XSLT 可能会运行而不会出错:

<xsl:template match="@*|node()">
    <xsl:copy>
        <xsl:apply-templates select="@*">
        <xsl:apply-templates select="node()">
            <xsl:sort select="@postid" data-type="text" order="descending"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>
于 2013-02-01T13:58:49.483 回答
2

这种转变

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

 <xsl:template match="year">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
    <xsl:apply-templates select="*">
      <xsl:sort select="@postid" data-type="number" order="descending"/>
    </xsl:apply-templates>
  </xsl:copy>
 </xsl:template>
</xsl:stylesheet>

应用于提供的 XML 文档时:

<posts>
    <year value="2013">
        <post postid="10030" postmonth="1">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
        <post postid="10040" postmonth="2">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
        <post postid="10050" postmonth="3">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
    </year>
    <year value="2012">
        <post postid="10010" postmonth="1">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
        <post postid="10015" postmonth="2">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
        <post postid="10020" postmonth="3">
            <othernode></othernode>
            <othernode2></othernode2>
        </post>
    </year>
</posts>

产生想要的正确结果:

<posts>
   <year value="2013">
      <post postid="10050" postmonth="3">
         <othernode/>
         <othernode2/>
      </post>
      <post postid="10040" postmonth="2">
         <othernode/>
         <othernode2/>
      </post>
      <post postid="10030" postmonth="1">
         <othernode/>
         <othernode2/>
      </post>
   </year>
   <year value="2012">
      <post postid="10020" postmonth="3">
         <othernode/>
         <othernode2/>
      </post>
      <post postid="10015" postmonth="2">
         <othernode/>
         <othernode2/>
      </post>
      <post postid="10010" postmonth="1">
         <othernode/>
         <othernode2/>
      </post>
   </year>
</posts>
于 2013-02-01T14:04:36.067 回答