使用Linq to XML操作RDLC報表參數
前一陣子工作中遇到這么一個問題,需要檢查幾十個RDLC報表,判斷其中是否存在幾個報表參數,若不存在則進行追加。當時我是純手工處理的,以記事本打開報表,檢查有沒有那幾個參數,沒有的話就手工添加進去一些XML片段。
在Visual Studio 2010 Ultimate RC 下測試通過
在RDLC報表中,報表參數由類似下面的XML進行描述:
……
<ReportParameters>
<ReportParameter Name="p_Country">
<DataType>String</DataType>
<Prompt>ReportParameter1</Prompt>
</ReportParameter>
<ReportParameter Name="p_Address">
<DataType>String</DataType>
<Prompt>ReportParameter1</Prompt>
</ReportParameter>
……
</ReportParameters>
……
RDL報表與RDLC報表是由RDL語言描述的,RDL = Report Definition Language 報表定義語言。
RDL規范至今已有四個版本:
|
Report server version |
RDL schema version |
|
SQL Server 2008 R2 |
2000 RDL |
|
2005 RDL | |
|
2008 RDL | |
|
2009 RDL | |
|
SQL Server 2008 |
2000 RDL |
|
2005 RDL | |
|
2008 RDL |
其中最新版本2009 RDL將于2010年5月隨同SQL Server 2008 R2 Reporting Services一起發布。由于RDL是基于XML的描述性語言,所以可以像操作XML那樣來操作RDL,進而操作報表中的元素。我將使用Linq to XML來操作RDL,解決前面修改報表參數的問題。
首先,我們來看下Visual Studio 2010中對RDLC報表支持的改變。
Visual Studio 2008中的RDLC的命名空間是這樣的:
<Report xmlns="http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner">
在Visual Studio 2010中,命名空間改變如下:
<Report xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition">
如果在VS 2010中打開之前版本的報表,會提示自動轉換。奇怪的是VS 2010中沒有采用RDL 2009規范,不知道等SQL Server 2008 R2正式發布后會不會更新。
此外,VS 2010中的RDLC設計界面也發生了變化,清一色的Reporting Services風格:

工具箱中多了一個儀表控件,可以實現指針效果:
針對即將發布的SQL Server 2008 R2,微軟也提供了Report Builder 3.0的測試版,可以在這里下載。注意:必須要先安裝SQL Server 2008 R2才能安裝Report Builder 3.0,此外還需要.NET Framework 3.5 With SP1。Report Builder 3.0 提供了新的控件:Map、Data Bar、SparkLine,提供更加友好的用戶體驗:

遺憾的是Report Builder 3.0依然不支持RDLC的編輯。
下面我們進入正題,以VS 2010中的RDL 2008規范為例進行測試。
創建一個RDLC報表,添加兩個報表參數:p_Country、p_Address。
以記事本打開RDLC報表,可以看到如下元素:
<Report xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition">
......
<ReportParameter Name="p_Country">
<DataType>String</DataType>
<Prompt>ReportParameter1</Prompt>
</ReportParameter>
<ReportParameter Name="p_Address">
<DataType>String</DataType>
<Prompt>ReportParameter1</Prompt>
</ReportParameter>
......
有兩個命名空間,一個前綴為rd,另一個是默認的命名空間。要使用Linq to XML操作RDL語言,首先要將其放到內存中:
代碼
{
FileStream file = new FileStream(v_strPath, FileMode.Open, FileAccess.ReadWrite);
XmlReader reader = XmlReader.Create(file);
XElement rdlc = XElement.Load(reader);
下面要將兩個命名空間添加進來:
代碼
XmlNamespaceManager mgr = new XmlNamespaceManager(nameTable);
mgr.AddNamespace("rd", "http://schemas.microsoft.com/SQLServer/reporting/reportdesigner");
mgr.AddNamespace("x", "http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition");
注意,對于默認的命名空間,需要隨意指定一個前綴,否則待會用Linq查詢不到元素。
然后判斷指定的參數是否存在,若不存在則進行添加:
代碼
<ReportParameter Name="p_City">
<DataType>String</DataType>
<Prompt>p_City</Prompt>
</ReportParameter>
*/
IEnumerable<XElement> report = from r in rdlc.XPathSelectElements(@"//x:ReportParameters/x:ReportParameter", mgr)
select r;
bool __bol = false;
foreach (var r in report)
{
if (r.Attribute("Name").Value == "p_City")
{
__bol = true;
}
}
if (!__bol)
{
report.First().AddAfterSelf(new XElement("{http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition}ReportParameter", new XAttribute("Name", "p_City"),
new XElement("{http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition}DataType", "String"),
new XElement("{http://schemas.microsoft.com/sqlserver/reporting/2008/01/reportdefinition}Prompt", "p_City")));
}
注意這里不能用剛才隨意添加的那個前綴“x”了,需要指定默認命名空間的全稱,用大括號括起來。
最后釋放占用的資源,保存所做的更改:
file.Close();
rdlc.Save(v_strPath);
此時打開報表后會看到我們剛才添加的參數:p_City

小結:
用類似的方法,可以操作任意的報表元素,甚至可以從頭開始創建一個完整的報表。但是可以看出這種方法相對繁瑣,而且容易出錯,如果需要大批量處理報表中的少量元素,還是不失為一種好方法。


浙公網安備 33010602011771號