@@ -171,7 +171,12 @@ static IPBanConfig()
171
171
private IPBanConfig ( XmlDocument doc , IDnsLookup dns = null , IDnsServerList dnsList = null , IHttpRequestMaker httpRequestMaker = null )
172
172
{
173
173
// deserialize with XmlDocument for fine grained control
174
- foreach ( XmlNode node in doc . SelectNodes ( "/configuration/appSettings/add" ) )
174
+ var appSettingsNodes = doc . SelectNodes ( "/configuration/appSettings/add" ) ;
175
+ if ( appSettingsNodes is null || appSettingsNodes . Count == 0 )
176
+ {
177
+ throw new InvalidDataException ( "Configuration is missing or has empty /configuration/appSettings element. This element name is case sensitive. Please check your config." ) ;
178
+ }
179
+ foreach ( XmlNode node in appSettingsNodes )
175
180
{
176
181
appSettings [ node . Attributes [ "key" ] . Value ] = node . Attributes [ "value" ] . Value ;
177
182
}
@@ -761,6 +766,106 @@ public static string ChangeConfigAppSetting(string config, string key, string ne
761
766
return doc . OuterXml ;
762
767
}
763
768
769
+ /// <summary>
770
+ /// Merge two configurations
771
+ /// </summary>
772
+ /// <param name="xmlBase">Base configuration</param>
773
+ /// <param name="xmlOverride">Override configuration</param>
774
+ /// <returns>Merged configuration</returns>
775
+ /// <exception cref="ArgumentException">Base xml is null or white space</exception>
776
+ public static XmlDocument MergeXml ( string xmlBase , string xmlOverride )
777
+ {
778
+ if ( string . IsNullOrWhiteSpace ( xmlBase ) )
779
+ {
780
+ throw new ArgumentException ( "Cannot merge null base xml" ) ;
781
+ }
782
+
783
+ XmlDocument docBase = new ( ) ;
784
+ docBase . LoadXml ( xmlBase ) ;
785
+
786
+ if ( string . IsNullOrWhiteSpace ( xmlOverride ) )
787
+ {
788
+ return docBase ;
789
+ }
790
+
791
+ XmlDocument docOverride = new ( ) ;
792
+ docOverride . LoadXml ( xmlOverride ) ;
793
+
794
+ XmlNode logFilesOverride = docOverride . SelectSingleNode ( "/configuration/LogFilesToParse/LogFiles" ) ;
795
+ XmlNode logFilesBase = docBase . SelectSingleNode ( "/configuration/LogFilesToParse/LogFiles" ) ?? logFilesOverride ;
796
+ if ( logFilesBase is not null &&
797
+ logFilesOverride is not null &&
798
+ logFilesBase != logFilesOverride )
799
+ {
800
+ foreach ( XmlNode overrideNode in logFilesOverride )
801
+ {
802
+ if ( overrideNode . NodeType == XmlNodeType . Element )
803
+ {
804
+ logFilesBase . AppendChild ( docBase . ImportNode ( overrideNode , true ) ) ;
805
+ }
806
+ }
807
+ }
808
+
809
+ XmlNode expressionsBlockOverride = docOverride . SelectSingleNode ( "/configuration/ExpressionsToBlock/Groups" ) ;
810
+ XmlNode expressionsBlockBase = docBase . SelectSingleNode ( "/configuration/ExpressionsToBlock/Groups" ) ?? expressionsBlockOverride ;
811
+ if ( expressionsBlockBase is not null &&
812
+ expressionsBlockOverride is not null &&
813
+ expressionsBlockBase != expressionsBlockOverride )
814
+ {
815
+ foreach ( XmlNode overrideNode in expressionsBlockOverride )
816
+ {
817
+ if ( overrideNode . NodeType == XmlNodeType . Element )
818
+ {
819
+ expressionsBlockBase . AppendChild ( docBase . ImportNode ( overrideNode , true ) ) ;
820
+ }
821
+ }
822
+ }
823
+
824
+ XmlNode expressionsNotifyOverride = docOverride . SelectSingleNode ( "/configuration/ExpressionsToNotify/Groups" ) ;
825
+ XmlNode expressionsNotifyBase = docBase . SelectSingleNode ( "/configuration/ExpressionsToNotify/Groups" ) ?? expressionsNotifyOverride ;
826
+ if ( expressionsNotifyBase is not null &&
827
+ expressionsNotifyOverride is not null &&
828
+ expressionsNotifyBase != expressionsNotifyOverride )
829
+ {
830
+ foreach ( XmlNode overrideNode in expressionsNotifyOverride )
831
+ {
832
+ if ( overrideNode . NodeType == XmlNodeType . Element )
833
+ {
834
+ expressionsNotifyBase . AppendChild ( docBase . ImportNode ( overrideNode , true ) ) ;
835
+ }
836
+ }
837
+ }
838
+
839
+ XmlNode appSettingsOverride = docOverride . SelectSingleNode ( "/configuration/appSettings" ) ;
840
+ XmlNode appSettingsBase = docBase . SelectSingleNode ( "/configuration/appSettings" ) ?? appSettingsOverride ;
841
+ if ( appSettingsBase is not null &&
842
+ appSettingsOverride is not null &&
843
+ appSettingsBase != appSettingsOverride )
844
+ {
845
+ foreach ( XmlNode overrideNode in appSettingsOverride )
846
+ {
847
+ if ( overrideNode . NodeType == XmlNodeType . Element )
848
+ {
849
+ string xpath = $ "/configuration/appSettings/add[@key='{ overrideNode . Attributes [ "key" ] . Value } ']";
850
+ XmlNode existing = appSettingsBase . SelectSingleNode ( xpath ) ;
851
+ if ( existing is null )
852
+ {
853
+ // create a new node
854
+ appSettingsBase . AppendChild ( docBase . ImportNode ( overrideNode , true ) ) ;
855
+ }
856
+ else
857
+ {
858
+ // replace existing node
859
+ string overrideValue = overrideNode . Attributes [ "value" ] ? . Value ?? string . Empty ;
860
+ existing . Attributes [ "value" ] . Value = overrideValue ;
861
+ }
862
+ }
863
+ }
864
+ }
865
+
866
+ return docBase ;
867
+ }
868
+
764
869
/// <inheritdoc />
765
870
public bool IsWhitelisted ( string entry ) => whitelistFilter . IsFiltered ( entry ) ;
766
871
0 commit comments