2009-07-27 42 views
5

Tôi muốn dịch một tệp XML với dữ liệu như sau:XSLT trên SSRS báo cáo

<FlatData> 
    <Details1_Collection> 
     <Details1 Customer1="Customer" Total1="3" /> 
     ... 
    </Details1_Collection> 
</FlatData> 

Các dữ liệu mà tôi quan tâm là các thuộc tính và giá trị của họ trong mỗi Details1. Vấn đề là những thuộc tính này không nhất thiết sẽ là như nhau trong mỗi tập tin XML Tôi muốn dịch, và tôi muốn có một XSL mục đích chung mà có thể xử lý như Details1 như sau đây:

<Details1 Customer1="Customer" Total1="3" /> 
<Details1 Name="Jim" Age="14" Weight="180" /> 
<Details1 Date="2009-07-27" Range="1-5" Option1="True" /> 

Những khác nhau Details1 sẽ không xảy ra trong cùng một tệp XML nguồn, nhưng thay vì trong các tệp khác nhau. Tuy nhiên, tôi muốn sử dụng cùng một XSL trên mỗi.

Tôi đã nghĩ tôi cần một cái gì đó như <xsl:value-of select="@attribute_name"/> nhưng tôi phải đặt gì cho @attribute_name khi tôi không biết trước thuộc tính nào sẽ có? Ngoài ra, làm thế nào để tôi nắm bắt được tên thuộc tính? Tôi muốn nổ nguồn XML trên một cái gì đó như:

<Details1> 
    <Customer1>Customer</Customer1> 
    <Total1>3</Total1> 
</Details1> 

Edit: cảm ơn vì những câu trả lời! Tôi đang gặp khó khăn hơn đầu ra sau đây, tuy nhiên:

<?xml version="1.0" encoding="UTF-8"?> 
<FlatData> 
<Details1_Collection></Details1_Collection> 
</FlatData> 

Tôi đã thử cả của lavinio và câu trả lời Jörn Horstmann của, cũng như cố gắng để kết hợp cả hai. Tôi chạy lệnh này:

msxsl.exe -o output.xml input.xml transform.xsl 

Tôi nghĩ rằng cái gì đó là nhận được theo cách này là một namespace trong file đầu vào:

<Report Name="MyReport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="MyReport"> 

Trả lời

4

Có sự gia tăng khó khăn do không gian tên Microsoft SQL Reporting Services 2008 là một phần của XML đầu vào. Ban đầu tôi không nhận ra rằng <Report Name="MyReport" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="MyReport"> là một dòng quan trọng. Cảm ơn Pavel Minaev vì số namespace comment. XSL sau làm việc để trích xuất các dữ liệu tôi muốn:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:a="EXQC005"> 
    <xsl:output method="xml" indent="yes" encoding="utf-8"/> 

    <xsl:template match="/"> 
    <xsl:for-each select="a:Report/a:FlatData/a:Details1_Collection/a:Details1"> 
     <xsl:element name="{name(.)}"> 
     <xsl:for-each select="@*"> 
      <xsl:element name="{name(.)}"> 
      <xsl:value-of select="."/> 
      </xsl:element> 
     </xsl:for-each> 
     </xsl:element> 
    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

Tôi nghĩ rằng tôi sẽ cố gắng để làm sạch này lên đến sử dụng apply-templates phong cách mà lavinio gợi ý. Cảm ơn cũng đến Jörn Horstmann cho mã select="@*" trong các vòng for-each. Sẽ rất thú vị khi tìm hiểu lý do tại sao báo cáo Dịch vụ báo cáo bị bán phá giá ban đầu với giá trị xmlns được đặt thành tên của báo cáo chứ không phải là schema URL.

Tôi sẽ tiếp tục cập nhật câu trả lời này khi tôi tinh chỉnh XSL này.

Edit: đây là một phiên bản namespace-agnostic từ đó, cho mỗi báo cáo khác nhau từ dịch vụ báo cáo, có vẻ như sẽ là một không gian tên khác nhau:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes" encoding="utf-8"/> 

    <xsl:template match="/"> 
    <xsl:for-each select="*[local-name()='Report']/*[local-name()='FlatData']/*[local-name()='Details1_Collection']/*[local-name()='Details1']"> 
     <Details> 
     <xsl:for-each select="@*"> 
      <xsl:element name="{name(.)}"> 
      <xsl:value-of select="."/> 
      </xsl:element> 
     </xsl:for-each> 
     </Details> 
    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 
3

Bạn có thể sử dụng "@*" để đề cập đến tất cả các thuộc tính, như những ví dụ:

  • <xsl:value-of select="@*"/>
  • <xsl:apply-templates select="@*"/>
  • <xsl:template match="@*">

Các <xsl:element name=""> xây dựng có thể được sử dụng để tạo ra một nguyên tố mới với tên tùy ý, và các chức năng name() hoặc local-name() sẽ trả lại tên của một thuộc tính cụ thể.

Để làm những gì bạn muốn, hãy thử một cái gì đó dọc theo những dòng:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:template match="/"> 
     <FlatData> 
      <Details1_Collection> 
       <xsl:apply-templates select="FlatData/Details1_Collection/Details1"/> 
      </Details1_Collection> 
     </FlatData> 
    </xsl:template> 
    <xsl:template match="Details1"> 
     <Details1> 
      <xsl:apply-templates select="@*"/> 
     </Details1> 
    </xsl:template> 
    <xsl:template match="@*"> 
     <xsl:element name="{name()}"> 
      <xsl:value-of select="."/> 
     </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 
2

Liệu Transformation này cung cấp cho các kết quả bạn muốn?

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

    <xsl:output method="xml" indent="yes" encoding="utf-8" /> 

    <xsl:template match="//Details1"> 
     <Details1> 
      <xsl:for-each select="@*"> 
       <xsl:element name="{name(.)}"><xsl:value-of select="." /></xsl:element> 
      </xsl:for-each> 
     </Details1> 
    </xsl:template> 

</xsl:stylesheet> 
+0

Điều này dẫn đến một tập tin XML với gần như là nhiều dòng như XML gốc, đầu vào, nhưng với tất cả chúng trống, hãy lưu dòng đầu tiên chứa ''. –

+0

Hóa ra tôi có một dòng trống thay vì dữ liệu tôi muốn vì vấn đề không gian tên; câu hỏi được cập nhật, thêm câu trả lời của riêng tôi. –

0

một cách khác để viết câu trả lời Jörn Horstmann (nếu bạn cần phải làm điều này với Details1, Details2, và vân vân ...) Sẽ là:

<xsl:template match="//Details1 | //Details2 | //whatever"> 
    <xsl:copy> 
    <xsl:apply-templates select="@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="@*"> 
    <xsl:element name="{name(.)}"> 
    <xsl:value-of select="." /> 
    </xsl:element> 
</xsl:template> 
0

Có lẽ cách đơn giản nhất để làm điều đó:

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

    <xsl:template match="/"> 
    <FlatData> 
     <xsl:copy-of select="//Details1" /> 
    </FlatData> 
    </xsl:template> 
</xsl:stylesheet> 
+1

Không thực sự - điều này chỉ sao chép các phần tử như vậy, và câu hỏi là về việc dịch các thuộc tính thành các phần tử. –

3

Để giải quyết vấn đề không gian tên (đối với cả hai câu trả lời), thêm một tuyên bố namespace với một tiền tố để XLST của bạn:

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

và sau đó sử dụng nó trong tất cả các biểu thức XPath của bạn để đủ điều kiện các yếu tố, ví dụ:

<xsl:template match="//r:Details1"> 
Các vấn đề liên quan