Question

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

Was it helpful?

Solution 2

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

OTHER TIPS

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

While adding use this namespace with following settings.

     XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
     namespaces.Add(string.Empty, string.Empty);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top