2013-02-01 15 views
7

Điều bắt đầu như một điều đơn giản đã trở nên khá rắc rối đối với XSLT noob.Phân loại XSLT - cách sắp xếp các nút con xml bên trong nút cha với thuộc tính

Cố gắng sắp xếp childNodes/giảm dần nhưng, sau khi thêm một thuộc tính để nút cha của họ, tôi nhận được một lỗi khi gỡ lỗi trong 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."

Giả sử tôi có XML đơn giản này:

<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> 

Tôi chuyển XPath vào xmldatasource để truy xuất nút <year> có liên quan, ví dụ: 2013. Sau đó, tôi cần phải sắp xếp con của mình <post> các nút giảm dần bằng cách sử dụng postid, vì vậy đối với <year value=2013>, postid = 10050 sẽ hiển thị đầu tiên khi được hiển thị.

Vì vậy, phải rõ ràng: Tôi chỉ quan tâm đến việc sắp xếp bên trong một nút <year>.

Trước khi tôi chia các nút vào nút riêng biệt (tức là xml/bài viết/bài) XSLT sau làm việc:

<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> 

Bây giờ XMLDataSource trống khi chạy do lỗi trên. Nếu tôi vượt qua tăng dần vào thứ tự cùng một xml được trả về rõ ràng (không chuyển đổi)

Câu hỏi: cách cập nhật XSLT ở trên (hoặc mới) để chứa thuộc tính nút cha (<year value="">)? Thông qua nghiên cứu, một câu trả lời cho biết "Tôi cần phải thêm tạo thuộc tính trước khi tạo thành phần". Điều này có ý nghĩa khi xem trình gỡ lỗi, các nút con được tạo thành theo thứ tự desc, nhưng thẻ năm bị thiếu thuộc tính của nó. Nhưng tôi không có một đầu mối thực sự về XSLT. Không thể thấy nó quá phức tạp nhưng chỉ không biết ngôn ngữ.

Bất kỳ trợ giúp nào, được đánh giá cao. Cảm ơn

Trả lời

5

Vì vậy, bạn có nói rằng bạn chỉ chuyển một phần tài liệu XML của mình (một nút <year>) tới bộ xử lý XSLT?

Bạn nên sử dụng mẫu riêng biệt trong năm, do đó, đó là mẫu duy nhất sử dụng sắp xếp. Làm thế nào được như sau:

<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> 

Tôi nghĩ rằng ở trên là một cách tiếp cận tốt hơn, nhưng tôi nghĩ rằng nguyên nhân gốc rễ của lỗi của bạn là nó được trộn lẫn các thuộc tính với các yếu tố khi nó đã làm việc phân loại. XSLT ban đầu của bạn có lẽ sẽ chạy mà không có lỗi nếu bạn chỉ đơn giản là đã làm điều này:

<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> 
+0

Vậy đó. Tuyệt vời nó hoạt động. Cảm ơn ông rất nhiều! Có, tôi chỉ chuyển nút một năm cho XSLT. Tôi chọn năm/bài đăng tôi muốn hiển thị. Sẽ cố gắng tìm ra cấu trúc mới của bạn và tìm hiểu cách đọc xslt. – JimXC

+0

Tại sao một người dùng 'data-type =" text "' trong trường hợp này? điều này rõ ràng tạo ra kết quả sai nếu giá trị 'postid' có thể có độ dài khác nhau. –

+0

Đó là một điểm tốt. Tôi đã sử dụng nó vì đó là XSLT ban đầu của JimXC được sử dụng và nó không phải là trọng tâm của câu hỏi của anh ấy, cộng với tôi đã không nhận thấy rằng các ID trong ví dụ của anh ấy là số. Nếu các ID được đảm bảo là số, thì 'data-type =" numeric "' sẽ thích hợp hơn. – JLRishe

2

chuyển đổi này:

<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> 

khi áp dụng trên tài liệu XML cung cấp:

<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> 

tạo ra kết quả mong muốn, chính xác:

<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> 
+0

Xác nhận điều này cũng hoạt động. Một lần nữa, vì lợi ích của riêng tôi, bạn đang sử dụng số trong kiểu dữ liệu - được hiểu. Nhưng áp phích trước được sử dụng select = post trong ứng dụng mẫu, bạn sử dụng *. Có gì khác biệt? Giả sử bạn đang phục vụ cho bất kỳ nút được đặt tên nào trong khi khác là bài cụ thể? – JimXC

+1

@JimXC, Bất cứ khi nào chúng ta biết rằng bất kỳ phần tử con nào của nút hiện tại là một 'bài', bằng cách sử dụng' * 'có thể hiệu quả hơn vì điều này tránh được một kiểm tra bởi bộ xử lý XSLT cho dù một đứa trẻ có phải là' bài' hay không. Ngoài ra, mã ngắn hơn theo cách này và viết nó nhanh hơn và dễ dàng hơn. –

+0

Xin cảm ơn. Không thể upvote hoặc +1 có tôi sợ. – JimXC