2009-05-16 35 views
9

Tôi có một tài liệu động XML đại diện cho một cấu trúc cây các loại, nhưng không vì vậy sử dụng con đường tách ra thuộc tính theo thứ tự tùy ý - như thế này:Tạo một cấu trúc cây lồng nhau từ một đường dẫn trong XSLT

<data>  
     <record ID="24" Name="category 1\sub category 1"/> 
     <record ID="26" Name="category 1"/>  
     <record ID="25" Name="category 1\sub category 1\sub category 2"/>  
     <record ID="27" Name="category 1\sub category 1\sub category 3"/>  
     ... 
    </data> 

tôi cần phải tìm ra một giải pháp mà 'bình thường hóa' XML để nó biến thành một cái gì đó như thế này:

<data>  
     <record ID="26" Name="category 1">  
     <record ID="24" Name="sub category 1">  
      <record ID="25" Name="sub category 2"/> 
      <record ID="27" Name="sub category 3"/>  
     </record> 
     </record> 
     ... 
    </data> 

về cơ bản tôi đã tự hỏi nếu điều này là một cái gì đó XSLT có thể có thể để giải quyết, và làm thế nào, chứ không phải hơn havin g để làm điều đó theo chương trình.

+0

@myso: "tiểu mục 3 "có cùng cấp với" danh mục phụ 2 "trong XML đầu vào của bạn. Nó không thể lồng nhau theo cách bạn hiển thị trong XML đầu ra của bạn. – Tomalak

+0

Vâng, sai lầm của tôi. Đã chỉnh sửa nó. – mysomic

Trả lời

18

Chắc chắn, không có vấn đề:

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

    <xsl:output indent="yes" /> 

    <xsl:template match="/data"> 
    <!-- copy the document element --> 
    <xsl:copy> 
     <!-- That's where we start: all "record" nodes that have no "\". --> 
     <xsl:apply-templates mode="recurse" select="/data/record[ 
     not(contains(@Name, '\')) 
     ]" /> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="record" mode="recurse"> 
    <xsl:param name="starting-path" select="''" /> 

    <!-- The record node and its ID attribute can be copied. --> 
    <xsl:copy> 
     <xsl:copy-of select="@ID" /> 

     <!-- Create the new "name" attribute. --> 
     <xsl:attribute name="Name"> 
     <xsl:value-of select="substring-after(@Name, $starting-path)" /> 
     </xsl:attribute> 

     <!-- Append a backslash to the current path. --> 
     <xsl:variable name="current-path" select="concat(@Name, '\')" /> 

     <!-- Select all "record" nodes that are one level deeper... --> 
     <xsl:variable name="children" select="/data/record[ 
     starts-with(@Name, $current-path) 
     and 
     not(contains(substring-after(@Name, $current-path), '\')) 
     ]" /> 

     <!-- ...and apply this template to them. --> 
     <xsl:apply-templates mode="recurse" select="$children"> 
     <xsl:with-param name="starting-path" select="$current-path" /> 
     </xsl:apply-templates> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

Output trên hệ thống của tôi:

<data> 
    <record ID="26" Name="category 1"> 
    <record ID="24" Name="sub category 1"> 
     <record ID="25" Name="sub category 2"></record> 
     <record ID="27" Name="sub category 3"></record> 
    </record> 
    </record> 
</data> 

Lưu ý rằng toàn bộ giải pháp dựa trên giả định rằng tất cả các con đường là kinh điển và không chứa dấu xồ nguợc trailing .

Cũng lưu ý rằng mọi phần tử "bản ghi" chưa từng có/mồ côi sẽ không ở đầu ra (trừ khi chúng ở cấp cơ sở, dĩ nhiên).

Một điều nữa: Chế độ mẫu ("recurse") là không cần thiết. Tôi đã bao gồm nó vì mẫu đang làm điều gì đó khá đặc biệt và có thể có một mẫu khác trong giải pháp của bạn khớp với các nút "ghi". Trong trường hợp này, giải pháp này có thể được giảm xuống mà không vi phạm bất cứ điều gì khác. Đối với giải pháp độc lập, các chế độ mẫu có thể bị xóa bất cứ lúc nào.

Oh, và điều cuối cùng: Nếu bạn muốn tài liệu kết quả để được sắp xếp theo tên, bao gồm <xsl:sort> element với <xsl:apply-templates> (cả hai lần xuất hiện), như vậy:

<xsl:apply-templates select="..."> 
    <xsl:sort select="@Name" data-type="text" order="ascending" /> 
</xsl:apply-templates> 
+0

Nó hoạt động hoàn hảo. Thật là một phản ứng tuyệt vời, cảm ơn bạn rất nhiều! – mysomic

+0

Bạn được chào đón. :-) – Tomalak

+6

Người đàn ông, bạn chỉ cần đá! – Cerebrus

Các vấn đề liên quan