1+ 'Orignal idea taken from this blog post : https://jaredzagelbaum.wordpress.com/category/reporting-services/
2+ 'Authored by Jared Zagelbaum 11/2014 jaredzagelbaum.wordpress.com
3+ 'Authored by Hendrik Groenewald 07/2015 h c g r o e n e w a l d [at] g m a i l . c o m
4+ 'Concept extended to be any node replacement, and in addition also copy all children nodes, and all children nodes of target node that are not replaced by template / source node
5+ ' PLEASE NOTE : de is given to the default XML namespace [ prefix ] therefore any default nodes need to have //de: as prefix in the XPATH search
6+ '========================================================================================================================================================================
7+ Sub CopyNodes( ByRef TargetDocument As System.Xml.XmlDocument, _
8+ ByRef TargetNode As System.Xml.XmlNode, _
9+ ByRef SourceNode As System.Xml.XmlNode, _
10+ ByVal TargetNameSpaceUri As String , _
11+ ByVal NodeLevel As Integer _
12+ )
13+
14+ 'Console.Writeline("")
15+ 'Console.Writeline("================================================================================")
16+ 'Console.Writeline("Inside CopyNodes procedure ")
17+ 'Console.Writeline("TargetDocument : " + TargetDocument.Name)
18+ 'Console.Writeline("TargetNode : " + TargetNode.Name)
19+ 'Console.Writeline("SourceNode : " + SourceNode.Name)
20+ 'Console.Writeline("SourceNodeType : " + SourceNode.NodeType.ToString())
21+ 'Console.Writeline("TargetNameSpaceUri : " + TargetNameSpaceUri)
22+ 'Console.Writeline("NodeLevel : " + NodeLevel.ToString())
23+ 'Console.Writeline("================================================================================")
24+
25+ If NodeLevel 1 Then 'Not the Target Root Node
26+
27+ Dim TargetChildNode As System.Xml.XmlNode = TargetDocument.CreateNode( SourceNode.NodeType, SourceNode.Name , TargetNameSpaceUri )
28+
29+ For Each attr As System.Xml.XmlAttribute in SourceNode.Attributes
30+ Dim newAttr As XmlAttribute = TargetDocument.CreateAttribute(attr.Name)
31+ newAttr.Value = attr.Value
32+ TargetChildNode.Attributes.Append(newAttr)
33+ Next 'For Each attr As System.Xml.XmlAttribute in SourceNode.Attributes
34+
35+ 'Console.Writeline(SourceNode.Name.ToString() + " has children : " + SourceNode.HasChildNodes.ToString() )
36+ If SourceNode.FirstChild.NodeType.ToString() = "Text" Or SourceNode.FirstChild.NodeType.ToString() = "CDATA" Then
37+ TargetChildNode.InnerText = SourceNode.InnerText
38+ End if
39+
40+ 'Console.Writeline("Append Child Node to TargetNode : " + TargetNode.Name)
41+ TargetNode.AppendChild(TargetChildNode)
42+
43+ For Each childNode As System.Xml.XmlNode in SourceNode.ChildNodes
44+ If childNode IsNot Nothing And _
45+ ( childNode.NodeType.ToString() = "Element" ) _
46+ Then
47+ CopyNodes(TargetDocument, TargetChildNode, childNode, TargetNameSpaceUri, NodeLevel + 1 )
48+ End If
49+ Next
50+
51+ Else
52+
53+ If Not SourceNode.HasChildNodes Then
54+ TargetNode.InnerText = SourceNode.InnerText
55+ End if
56+
57+ For Each attr As System.Xml.XmlAttribute in SourceNode.Attributes
58+ Dim newAttr As XmlAttribute = TargetDocument.CreateAttribute(attr.Name)
59+ newAttr.Value = attr.Value
60+ TargetNode.Attributes.Append(newAttr)
61+ Next 'For Each attr As System.Xml.XmlAttribute in SourceNode.Attributes
62+
63+ For Each childNode As System.Xml.XmlNode in SourceNode.ChildNodes
64+ If childNode IsNot Nothing And _
65+ ( childNode.NodeType.ToString() = "Element" ) _
66+ Then
67+ CopyNodes(TargetDocument, TargetNode, childNode, TargetNameSpaceUri, NodeLevel + 1 )
68+ End If
69+ Next
70+
71+ End If
72+
73+ End Sub
74+
75+ '========================================================================================================================================================================
76+
77+ Sub CopyRemainingChildNodes ( ByRef TargetDocument As System.Xml.XmlDocument, _
78+ ByRef TargetNode As System.Xml.XmlNode, _
79+ ByRef SourceNode As System.Xml.XmlNode, _
80+ ByVal TargetNameSpaceUri As String , _
81+ ByVal NodeLevel As Integer _
82+ )
83+
84+ Dim NodeExistsInTarget As Boolean = False
85+
86+ For Each SourceChildNode As System.Xml.XmlNode in SourceNode.ChildNodes
87+
88+ NodeExistsInTarget = false
89+
90+ For Each TargetChildNode As System.Xml.XmlNode in TargetNode.ChildNodes
91+ If TargetChildNode.Name = SourceChildNode.Name Then
92+ NodeExistsInTarget = true
93+ End if
94+ Next
95+
96+ If Not NodeExistsInTarget Then
97+ 'Console.Writeline("Node found in Source that is not in Target : " + )
98+ CopyNodes(TargetDocument, TargetNode, SourceChildNode, TargetNameSpaceUri, NodeLevel)
99+ End If
100+
101+ Next
102+
103+ End Sub
104+
105+ '========================================================================================================================================================================
106+
107+ Sub Main()
108+
109+ Dim ScriptLoggingLocation as String = "E:\SSRS_Updates\ReportEditing_Update_Logo.log"
110+ Dim ScriptLoggingReportsWithoutImages As String = "E:\SSRS_Updates\ReportsWithoutImages.log"
111+
112+ Dim SourceItemName As String = "Capfin_Report_Template" 'Source Report Name
113+ Dim SourceNodeDefinition As String = "//de:Image[@Name=""LogoName""]" 'XPATH for SourceNode
114+
115+ Dim DestinationItemsDefinition As String = ""
116+ Dim DestinationNodeDefinition As String = "//de:Image[@Name=""Image1?" or @Name= "" Image2? "]"
117+
118+ Dim docDestination As New System.Xml.XmlDocument
119+ Dim docSource As New System.Xml.XmlDocument
120+ Dim nsmanagerdocSource As New XmlNamespaceManager(docSource.NameTable)
121+
122+ Dim sourceNode As System.Xml.XmlNode
123+ 'Dim destinationNode As System.Xml.XmlNode
124+ Dim reportDefinition As Byte () = Nothing
125+
126+ 'ReportItems
127+ Dim items As CatalogItem() = rs.ListChildren( "/" , True )
128+
129+ 'Find Source Document and Node
130+ For Each item As CatalogItem In items
131+ If item.TypeName = "Report" And item.Name = SourceItemName Then
132+ Console.Writeline( "Found template" )
133+
134+ reportDefinition = rs.GetItemDefinition(item.Path)
135+ Dim stream As New MemoryStream(reportDefinition)
136+ docSource.Load(stream)
137+
138+ 'Add all Report NameSpaces to SourceNameSpaceManager
139+
140+ Dim SourceNameSpace_Prefix as String = String .Empty
141+ For Each attr As System.Xml.XmlAttribute in docSource.DocumentElement.Attributes
142+ if attr.Name.Contains( "xmlns" ) Then
143+ 'Console.Writeline(attr.LocalName)
144+ 'Console.Writeline(attr.Name)
145+ 'Console.Writeline(attr.Prefix)
146+ 'Console.Writeline(attr.InnerText)
147+ 'Console.Writeline("==============")
148+ 'Console.Writeline("")
149+
150+ If attr.LocalName = "xmlns" Then
151+ 'SourceNameSpace_Prefix = String.Empty
152+ SourceNameSpace_Prefix = "de"
153+ Else
154+ SourceNameSpace_Prefix = attr.LocalName
155+ End If
156+
157+ nsmanagerdocSource.AddNamespace(SourceNameSpace_Prefix,attr.InnerText)
158+ End If
159+ Next
160+
161+ Console.Writeline( "Source Node Search Criteria : " + SourceNodeDefinition)
162+
163+ 'Load SourceNode into XmlNode
164+ sourceNode = docSource.SelectSingleNode(SourceNodeDefinition, nsmanagerdocSource)
165+
166+ Exit For
167+ End If 'If item.TypeName = "Report" And item.Name = SourceItemName Then
168+ Next 'For Each item As CatalogItem In items
169+
170+ If sourceNode IsNot Nothing Then
171+
172+ Console.Writeline( "SourceNode Found and loaded" )
173+
174+ 'Loop through all Reports in Calalog
175+ Console.Writeline( "Loop through all Destination Items / Reports" )
176+
177+ For Each item As CatalogItem In items
178+ If item.TypeName = "Report" _
179+ And item.Name SourceItemName _
180+ Then
181+
182+ Console.Writeline(item.Path)
183+
184+ reportDefinition = rs.GetItemDefinition(item.Path)
185+
186+ Dim stream As New MemoryStream(reportDefinition)
187+ Dim outstream As New MemoryStream()
188+
189+ docDestination.Load(stream)
190+
191+ Dim nsmanagerdocDestination As New XmlNamespaceManager(docDestination.NameTable)
192+
193+ Dim DestinationNameSpace_Prefix as String = String .Empty
194+ Dim DestinationDefaultNameSpaceUri as String = ""
195+
196+ For Each attr As System.Xml.XmlAttribute in docDestination.DocumentElement.Attributes
197+ if attr.Name.Contains( "xmlns" ) Then
198+
199+ If attr.LocalName = "xmlns" Then
200+
201+ 'Console.Writeline(attr.LocalName)
202+ 'Console.Writeline(attr.Name)
203+ 'Console.Writeline(attr.Prefix)
204+ 'Console.Writeline(attr.InnerText)
205+ 'Console.Writeline("==============")
206+ 'Console.Writeline("")
207+
208+ 'DestinationNameSpace_Prefix = String.Empty
209+ DestinationNameSpace_Prefix = "de"
210+ DestinationDefaultNameSpaceUri = attr.InnerText
211+ Else
212+ DestinationNameSpace_Prefix = attr.LocalName
213+ End If
214+
215+ 'Console.Writeline("Adding Namespace to manager " + DestinationNameSpace_Prefix )
216+ nsmanagerdocDestination.AddNamespace(DestinationNameSpace_Prefix,attr.InnerText)
217+
218+ 'Console.Writeline("Namespace Added : " + DestinationNameSpace_Prefix )
219+ 'Console.Writeline("")
220+
221+ End If 'if attr.Name.Contains("xmlns") Then
222+ Next 'For Each attr As System.Xml.XmlAttribute in docDestination.DocumentElement.Attributes
223+
224+ 'Create ReplacementNodeTemplate
225+ Dim ReplacementNodeTemplate As System.Xml.XmlNode = docDestination.CreateNode( sourceNode.NodeType, sourceNode.Name , DestinationDefaultNameSpaceUri )
226+
227+ CopyNodes(docDestination, ReplacementNodeTemplate, sourceNode, DestinationDefaultNameSpaceUri, 1 )
228+
229+ 'Locate all Matching Destination Nodes
230+ For Each DestinationNode as XmlNode in docDestination.SelectNodes(DestinationNodeDefinition, nsmanagerdocDestination)
231+
232+ Dim DestinationNodeValue_Text As String = ""
233+
234+ For NodeCounter As Integer = 0 To (DestinationNode.ChildNodes.Count- 1 )
235+ if DestinationNode.ChildNodes(NodeCounter).Name = "Value" Then
236+ DestinationNodeValue_Text = DestinationNode.ChildNodes(NodeCounter).InnerText
237+ Exit For
238+ End If
239+ Next
240+
241+ 'If DestinationNodeValue IsNot Nothing Then
242+ ' Dim DestinationNodeValue_Text = DestinationNodeValue.InnerText
243+
244+ If DestinationNodeValue_Text = "capfin_logo" _
245+ or DestinationNodeValue_Text = "CapfinLogo" _
246+ or DestinationNodeValue_Text = "CapfinLogo_New" _
247+ or DestinationNodeValue_Text = "CapfinLogo2" _
248+ or DestinationNodeValue_Text = "SmartLogo" _
249+ Then
250+
251+ 'ScriptLoggingLocation
252+ Console.Writeline(item.Path + " : Matching Node Found : " + DestinationNode.Attributes( "Name" ).Value.ToString())
253+ File.AppendAllText(ScriptLoggingLocation, DateTime.Now.ToString() + " : " + item.Path + " : Matching Node Found : " + DestinationNode.Attributes( "Name" ).Value.ToString() + Environment.NewLine)
254+
255+ 'Identify ParentNode Replace DestinationNode with ReplacementNode
256+ Dim DestinationParentNode As System.Xml.XmlNode = DestinationNode.ParentNode
257+
258+ Dim ReplacementNode As System.Xml.XmlNode = ReplacementNodeTemplate
259+
260+ 'Copy Target Children Nodes, which are not part of Source Node
261+ CopyRemainingChildNodes(docDestination, ReplacementNode, DestinationNode, DestinationDefaultNameSpaceUri, 2 )
262+
263+ 'Console.Writeline(DestinationParentNode.Name)
264+ Console.Writeline(item.Path + " : Replace DestinationNode with ReplacementNode : " + DestinationNode.Attributes( "Name" ).Value.ToString() )
265+ DestinationParentNode.ReplaceChild( ReplacementNode ,DestinationNode)
266+
267+ 'If The SourceNode is an Image with External Source, replacing an embedded image within report, remove embedded image, check if last Embedded image,if so remove ParentNode as well
268+ If ReplacementNode.Name = "Image" And ReplacementNode.ChildNodes( 0 ).InnerText = "External" And DestinationNode.ChildNodes( 0 ).InnerText = "Embedded" Then
269+
270+ Dim ImageEmbeddedSourceName as String = ""
271+
272+ For NodeCounter As Integer = 0 To (DestinationNode.ChildNodes.Count- 1 )
273+ if DestinationNode.ChildNodes(NodeCounter).Name = "Value" Then
274+ ImageEmbeddedSourceName = DestinationNode.ChildNodes(NodeCounter).InnerText
275+ Exit For
276+ End If
277+ Next
278+
279+ Console.Writeline(DestinationNode.Attributes( "Name" ).Value.ToString() + " : ImageEmbeddedSourceName : " + ImageEmbeddedSourceName)
280+
281+ Dim EmbeddedImageNode_Criteria AS String = "//de:EmbeddedImage[@Name=""" + ImageEmbeddedSourceName + """]"
282+
283+ Dim EmbeddedImageNode As System.Xml.XmlNode = docDestination.SelectSingleNode(EmbeddedImageNode_Criteria, nsmanagerdocDestination)
284+
285+ If EmbeddedImageNode IsNot Nothing Then
286+
287+ If EmbeddedImageNode.ParentNode.ChildNodes.Count > 1 Then
288+
289+ Console.Writeline(item.Path + " : Only Removed Embedded Image : " + ImageEmbeddedSourceName)
290+ 'File.AppendAllText(ScriptLoggingLocation, item.Path + " : Only Removed Embedded Image : " + ImageEmbeddedSourceName + Environment.NewLine)
291+
292+ EmbeddedImageNode.ParentNode.RemoveChild(EmbeddedImageNode)
293+ Else
294+ Console.Writeline(item.Path + " : Removed Embedded Image + Parent Node : " + ImageEmbeddedSourceName)
295+ 'File.AppendAllText(ScriptLoggingLocation, item.Path + " : Removed Embedded Image + Parent Node : " + ImageEmbeddedSourceName + Environment.NewLine)
296+
297+ Dim EmbeddedImageNodeParentNode As System.Xml.XmlNode = EmbeddedImageNode.ParentNode
298+
299+ EmbeddedImageNode.ParentNode.RemoveChild(EmbeddedImageNode)
300+ EmbeddedImageNodeParentNode.ParentNode.RemoveChild(EmbeddedImageNodeParentNode)
301+
302+ End If
303+
304+ End If
305+
306+ End if
307+
308+ End if
309+ 'End if
310+ Next 'For Each DestinationNode as XmlNode in docDestination.SelectNodes(DestinationNodeDefinition, nsmanagerdocDestination)
311+
312+ docDestination.Save(outstream)
313+ reportDefinition = outstream.ToArray()
314+ rs.SetItemDefinition(item.Path, reportDefinition, Nothing )
315+
316+ stream.Dispose()
317+ outstream.Dispose()
318+
319+ End If 'If item.TypeName = "Report" And Item.Name SourceItemName Then
320+ Next 'For Each item As CatalogItem In items
321+
322+ Else
323+ Console.Writeline( "SourceNode is Nothing" )
324+ End if 'If sourceNode IsNot Nothing Then
325+
326+ End Sub
0 commit comments