Reputation: 82196
I have 287 SSRS reports (XML files), where I need to add a parameter.
They all start like this:
<?xml version="1.0" encoding="utf-8"?>
<Report xmlns="http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner">
<DataSources>
<DataSource Name="COR_Basic">
<rd:DataSourceID>addde073-f37c-4b59-ae3a-25231ffc0ec6</rd:DataSourceID>
<DataSourceReference>COR_Basic</DataSourceReference>
</DataSource>
</DataSources>
<InteractiveHeight>29.7cm</InteractiveHeight>
<ReportParameters>
<ReportParameter Name="in_report_name">
<DataType>String</DataType>
<DefaultValue>
<Values>
<Value>=Globals!ReportName</Value>
</Values>
</DefaultValue>
<Prompt>Report Name</Prompt>
<Hidden>true</Hidden>
</ReportParameter>
<ReportParameter Name="in_mandant">
<DataType>String</DataType>
<DefaultValue>
<Values>
<Value>0</Value>
</Values>
</DefaultValue>
<Prompt>in_mandant</Prompt>
<Hidden>true</Hidden>
</ReportParameter>
Now I want to automagically add the "proc" parameter to all reports.
Which means I need to insert this bit of XML
<ReportParameter Name="proc">
<DataType>String</DataType>
<DefaultValue>
<Values>
<Value>MyTestValue</Value>
</Values>
</DefaultValue>
<Prompt>MyPromptText</Prompt>
<Hidden>true</Hidden>
</ReportParameter>
after
<ReportParameter Name="in_mandant">
...
</ReportParameter>
This is the code I have so far:
public static System.Xml.XmlDocument File2XmlDocument(string strFileName)
{
// http://blogs.msdn.com/b/tolong/archive/2007/11/15/read-write-xml-in-memory-stream.aspx
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
// doc.Load(memorystream);
// doc.Load(FILE_NAME);
using (System.Xml.XmlTextReader xtrReader = new System.Xml.XmlTextReader(strFileName))
{
doc.Load(xtrReader);
xtrReader.Close();
} // End Using xtrReader
return doc;
} // End Function File2XmlDocument
public static System.Xml.XmlNamespaceManager GetReportNamespaceManager(System.Xml.XmlDocument doc)
{
System.Xml.XmlNamespaceManager nsmgr = new System.Xml.XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("dft", "http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition");
return nsmgr;
} // End Function GetReportNamespaceManager
public static void AddProc(string strFilename)
{
System.Xml.XmlDocument doc = File2XmlDocument(strFilename);
System.Xml.XmlElement root = doc.DocumentElement;
System.Xml.XmlNamespaceManager nsmgr = GetReportNamespaceManager(doc);
System.Xml.XmlNode xnMandant = root.SelectSingleNode("/dft:Report/dft:ReportParameters/dft:ReportParameter[@Name=\"in_mandant\"]", nsmgr);
string strReportName = System.IO.Path.GetFileNameWithoutExtension(strFilename);
if (xnMandant != null)
{
LogMessage("{0}\t{1}", strReportName, xnMandant.FirstChild.Value);
string frag = @"<ReportParameter Name=""proc"">
<DataType>String</DataType>
<DefaultValue>
<Values>
<Value>MyTestValue</Value>
</Values>
</DefaultValue>
<Prompt>MyPromptText</Prompt>
<Hidden>true</Hidden>
</ReportParameter>";
System.Xml.XmlDocumentFragment xmlDocFrag = doc.CreateDocumentFragment();
xmlDocFrag.InnerXml = frag;
System.Xml.XmlNode xn = xnMandant.ParentNode.InsertAfter(xmlDocFrag, xnMandant);
Console.WriteLine(xn.OuterXml);
}
else
LogMessage("{0}\tKein Parameter in_mandant", strReportName);
SaveDocument(doc, strFilename);
} // End Sub PrintStichtag
This inserts the XML-Fragment at the right location, but I have a xmlns=""
after "proc"
.
<ReportParameter Name="proc" xmlns="">
<DataType>String</DataType>
<DefaultValue>
<Values>
<Value>MyTestValue</Value>
</Values>
</DefaultValue>
<Prompt>MyPromptText</Prompt>
<Hidden>true</Hidden>
</ReportParameter>
How can I avoid the empty xmlns attribute ?
(Short of loading the xml file as text and doing string.replace) .
Upvotes: 1
Views: 4393
Reputation: 147
While adding use this namespace with following settings.
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add(string.Empty, string.Empty);
Upvotes: 0
Reputation: 82196
It seems like this isn't possible at all ("thanks" to read-only property).
The only way around it is doing a replace on the OuterXml of the document, and reloading the document.
public static void SaveDocument(System.Xml.XmlDocument doc, string strFilename, bool bDoReplace)
{
string strSavePath = GetSavePath();
strSavePath = System.IO.Path.Combine(strSavePath, System.IO.Path.GetFileName(strFilename));
if (bDoReplace)
{
doc.LoadXml(doc.OuterXml.Replace("xmlns=\"\"", ""));
// doc.LoadXml(doc.OuterXml.Replace(strTextToReplace, strReplacementText));
}
using (System.Xml.XmlTextWriter xtw = new System.Xml.XmlTextWriter(strSavePath, System.Text.Encoding.UTF8))
{
xtw.Formatting = System.Xml.Formatting.Indented; // if you want it indented
xtw.Indentation = 4;
xtw.IndentChar = ' ';
doc.Save(xtw);
} // End Using xtw
} // End Sub SaveDocument
Upvotes: 2
Reputation: 1501043
How can I avoid the empty xmlns attribute ?
Create the elements in the right namespace. Due to namespace defaulting, all your elements should be in the http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition
namespace.
You could try inserting the fragment and then set its InnerXml
value - it's possible that that will apply namespace defaulting appropriately.
Personally, however, I'd use LINQ to XML which makes namespace handling much, much simpler - and then construct the elements programmatically instead of parsing them from text. In fact, I'd construct the elements programmatically anyway rather than setting the InnerXml
- it will make it easier to control precisely things like namespaces, as you can specify them when you construct the elements.
(I'd also strongly advise the use of using
directives, to avoid your code being peppered with fully qualified names everywhere.)
Upvotes: 3