-3

I can't figure out how to add the nodes under the Page XML element. I tried a to add the missing nodes, but could only add them to the end of the XML script. I can modify the nodes if they already exist, but can't add them. My script modifies the report XML by copying the nodes from a template report to each report on the report server. This is to maintain a consistent header and footer for each report deployed to the report server.

Script to modify XML

Public Sub Main()
    '--------------------------------------------------------------------------------------------------------------------
    ' Purpose:   Script to apply custom header and footer from a template report to all reports on ReportServer
    ' Notes:     uses Mgmt2010 endpoint / executable against stand alone or SharePoint integrated instance
    '            Save file as .rss extension and run using rs.exe from command line.
    ' Reference: https://jaredzagelbaum.wordpress.com/2014/11/14/update-all-ssrs-reportheaders/
    '            https://docs.microsoft.com/en-us/sql/reporting-services/tools/rs-exe-utility-ssrs?view=sql-server-2017
    ' Example:   rs -s http://localhost/reportserver -i D:\Scripts\Apply_Header_Footer.rss -e Mgmt2010 -v parentFolder="Test"
    '--------------------------------------------------------------------------------------------------------------------
    Dim reportDefinition As Byte() = Nothing
    Dim templateDoc As New System.XML.XmlDocument
    Dim reportDoc As New System.XML.XmlDocument
    Dim nsmanager As New XmlNamespaceManager(templateDoc.NameTable)
    Dim templatePath As String = "/_Custom/Template"
    Dim templateHeader As System.XML.XmlElement = Nothing
    Dim templateFooter As System.XML.XmlElement = Nothing
    Dim reportHeader As System.XML.XmlElement = Nothing
    Dim reportFooter As System.XML.XmlElement = Nothing
    Dim reportPage As System.XML.XmlElement = Nothing
    nsmanager.AddNamespace("rd", "http://schemas.microsoft.com/sqlserver/reporting/2016/01/reportdefinition")
    Dim items As CatalogItem() = rs.ListChildren("/", True)

    parentFolder = "/" + parentFolder

    Try
        For Each item As CatalogItem In items
            If item.TypeName = "Report" And item.Path = templatePath Then
                reportDefinition = rs.GetItemDefinition(item.Path)
                Dim stream1 As New MemoryStream(reportDefinition)
                templateDoc.Load(stream1)
                stream1.Dispose()
                Exit For
            End If
        Next

        templateHeader = templateDoc.SelectSingleNode("/rd:Report/rd:ReportSections/rd:ReportSection/rd:Page/rd:PageHeader", nsmanager)
        templateFooter = templateDoc.SelectSingleNode("/rd:Report/rd:ReportSections/rd:ReportSection/rd:Page/rd:PageFooter", nsmanager)

        For Each item As CatalogItem In items
            If item.TypeName = "Report" And (item.Path.StartsWith(parentFolder)) And Not (item.Name.StartsWith("SubRep")) Then
                reportDefinition = rs.GetItemDefinition(item.Path)
                Dim stream2 As New MemoryStream(reportDefinition)
                Dim outstream2 As New MemoryStream()
                reportDoc.Load(stream2)
                Console.WriteLine("Report: " + item.Name)
                Console.WriteLine("Report Path: " + item.Path)
                reportHeader = reportDoc.SelectSingleNode("/rd:Report/rd:ReportSections/rd:ReportSection/rd:Page/rd:PageHeader", nsmanager)
                reportFooter = reportDoc.SelectSingleNode("/rd:Report/rd:ReportSections/rd:ReportSection/rd:Page/rd:PageFooter", nsmanager)
                reportPage = reportDoc.SelectSingleNode("/rd:Report/rd:ReportSections/rd:ReportSection/rd:Page", nsmanager)
                Try
                    reportHeader.InnerXml = templateHeader.InnerXml
                    Console.WriteLine("Update Header: " + item.Path)
                Catch ex As NullReferenceException
                    Console.WriteLine("Add Header: " + item.Path)
                End Try
                Try
                    reportFooter.InnerXml = templateFooter.InnerXml
                    Console.WriteLine("Update Footer: " + item.Path)
                Catch ex As NullReferenceException
                    Console.WriteLine("Add Footer: " + item.Path)
                End Try
                reportDoc.Save(outstream2)
                reportDefinition = outstream2.ToArray()
                rs.SetItemDefinition(item.Path, reportDefinition, Nothing)
                stream2.Dispose()
                outstream2.Dispose()
            End If
        Next

    Catch ex As Exception
        Console.WriteLine(ex.ToString())

    End Try

End Sub

What I've tried to add the missing nodes

Console.WriteLine("attempt 1..." + item.Path)
Dim root As XmlNode = reportDoc.DocumentElement
root.AppendChild(templateHeader)
Dim elem As System.XML.XmlElement = reportDoc.CreateElement("PageHeader")
reportDoc.DocumentElement.AppendChild(elem)
reportDoc.Save(Console.Out)


Console.WriteLine("attempt 2..." + item.Path)
Dim newHeader As XmlNode = reportDoc.ImportNode(templateHeader, True)
reportPage.InsertAfter(templateHeader, reportPage.LastChild) 
reportDoc.Save(Console.Out)


Console.WriteLine("attempt 3..." + item.Path)
Dim elem As System.XML.XmlElement = reportDoc.CreateElement("PageHeader")
Dim docNodes As System.XML.XmlNodeList = reportDoc.LastChild.ChildNodes()

For Each node As System.XML.XmlNode In docNodes
    If node.Name = "rd:Page" Then
        node.AppendChild(elem)
    End If
Next
reportDoc.Save(Console.Out)

Example of the XML template with the nodes I want to add highlighted below

Report XML

References:

Original Script for .rss file

Microsoft Reference for rs.exe

aduguid
  • 2,682
  • 6
  • 15
  • 34
  • Possible duplicate of [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – zaggler May 28 '18 at 03:20
  • 2
    @aduguid...you can but you will have to create a new report object before sending. You receive the XML, copy to a `new` XML Object, validate and insert your content requirements, then pass this `new` object on to the next endpoint – GoldBishop Jun 04 '18 at 15:05

1 Answers1

1

As we spoke,

Your goal is to create a copy of the original, make the modifications necessary and then save the modified file.

I find I have to do this, when dealing with Configuration Settings (App and/or Web) in .Net.

GoldBishop
  • 2,586
  • 4
  • 42
  • 74