| 1 | #Region "Microsoft.VisualBasic::a255f72cf04e575d0c02114eada3381f, Microsoft.VisualBasic.Core\Extensions\Doc\XmlExtensions.vb" 
 | 
  | 2 | 
 | 
  | 3 | 
 | 
  | 4 | 
 | 
  | 5 | 
 | 
  | 6 | 
 | 
  | 7 | 
 | 
  | 8 | 
 | 
  | 9 | 
 | 
  | 10 | 
 | 
  | 11 | 
 | 
  | 12 | 
 | 
  | 13 | 
 | 
  | 14 | 
 | 
  | 15 | 
 | 
  | 16 | 
 | 
  | 17 | 
 | 
  | 18 | 
 | 
  | 19 | 
 | 
  | 20 | 
 | 
  | 21 | 
 | 
  | 22 | 
 | 
  | 23 | 
 | 
  | 24 | 
 | 
  | 25 | 
 | 
  | 26 | 
 | 
  | 27 | 
 | 
  | 28 | 
 | 
  | 29 | 
 | 
  | 30 | 
 | 
  | 31 | 
 | 
  | 32 | 
 | 
  | 33 | 
 | 
  | 34 | 
 | 
  | 35 | 
 | 
  | 36 | 
 | 
  | 37 | 
 | 
  | 38 | 
 | 
  | 39 | 
 | 
  | 40 | 
 | 
  | 41 | 
 | 
  | 42 | 
 | 
  | 43 | 
 | 
  | 44 | #End Region 
 | 
  | 45 | 
 | 
  | 46 | Imports System.IO 
 | 
  | 47 | Imports System.Reflection 
 | 
  | 48 | Imports System.Runtime.CompilerServices 
 | 
  | 49 | Imports System.Text 
 | 
  | 50 | Imports System.Text.RegularExpressions 
 | 
  | 51 | Imports System.Xml 
 | 
  | 52 | Imports System.Xml.Serialization 
 | 
  | 53 | Imports Microsoft.VisualBasic.CommandLine.Reflection 
 | 
  | 54 | Imports Microsoft.VisualBasic.Language 
 | 
  | 55 | Imports Microsoft.VisualBasic.Scripting.MetaData 
 | 
  | 56 | Imports Microsoft.VisualBasic.Text 
 | 
  | 57 | Imports Microsoft.VisualBasic.Text.Xml 
 | 
  | 58 | Imports r = System.Text.RegularExpressions.Regex 
 | 
  | 59 | 
 | 
  | 60 | <Package("Doc.Xml", Description:="Tools for read and write sbml, KEGG document, etc, xml based documents...")> 
 | 
  | 61 | Public Module XmlExtensions 
 | 
  | 62 | 
 | 
  | 63 | 
 | 
  | 64 | 
 | 
  | 65 | 
 | 
  | 66 | 
 | 
  | 67 | 
 | 
  | 68 | Public Function SafeLoadXml(Of T)(xml$, 
 | 
  | 69 | Optional encoding As Encodings = Encodings.Default, 
 | 
  | 70 | Optional preProcess As Func(Of String, String) = Nothing) As T 
 | 
  | 71 | Return xml.LoadXml(Of T)(encoding.CodePage, False, preProcess) 
 | 
  | 72 | End Function 
 | 
  | 73 | 
 | 
  | 74 | 
 | 
  | 75 | 
 | 
  | 76 | 
 | 
  | 77 | 
 | 
  | 78 | 
 | 
  | 79 | 
 | 
  | 80 | 
 | 
  | 81 | 
 | 
  | 82 | 
 | 
  | 83 | 
 | 
  | 84 | 
 | 
  | 85 | 
 | 
  | 86 | 
 | 
  | 87 | 
 | 
  | 88 | 
 | 
  | 89 | <Extension> Public Function LoadXml(Of T)(xmlFile$, 
 | 
  | 90 | Optional encoding As Encoding = Nothing, 
 | 
  | 91 | Optional throwEx As Boolean = True, 
 | 
  | 92 | Optional preprocess As Func(Of String, String) = Nothing, 
 | 
  | 93 | Optional stripInvalidsCharacter As Boolean = False) As T 
 | 
  | 94 | Dim type As Type = GetType(T) 
 | 
  | 95 | Dim obj As Object = xmlFile.LoadXml( 
 | 
  | 96 | type, encoding, throwEx, 
 | 
  | 97 | preprocess, 
 | 
  | 98 | stripInvalidsCharacter:=stripInvalidsCharacter 
 | 
  | 99 | ) 
 | 
  | 100 | 
 | 
  | 101 | If obj Is Nothing Then 
 | 
  | 102 | 
 | 
  | 103 | Return Nothing 
 | 
  | 104 | Else 
 | 
  | 105 | Return DirectCast(obj, T) 
 | 
  | 106 | End If 
 | 
  | 107 | End Function 
 | 
  | 108 | 
 | 
  | 109 | 
 | 
  | 110 | 
 | 
  | 111 | 
 | 
  | 112 | 
 | 
  | 113 | 
 | 
  | 114 | 
 | 
  | 115 | Xml文件的预处理操作</param> 
 | 
  | 116 | 
 | 
  | 117 | 
 | 
  | 118 | 
 | 
  | 119 | <ExportAPI("LoadXml")> 
 | 
  | 120 | <Extension> Public Function LoadXml(xmlFile$, type As Type, 
 | 
  | 121 | Optional encoding As Encoding = Nothing, 
 | 
  | 122 | Optional ThrowEx As Boolean = True, 
 | 
  | 123 | Optional preprocess As Func(Of String, String) = Nothing, 
 | 
  | 124 | Optional stripInvalidsCharacter As Boolean = False) As Object 
 | 
  | 125 | 
 | 
  | 126 | If Not xmlFile.FileExists(ZERO_Nonexists:=True) Then 
 | 
  | 127 | Dim exMsg$ = $"{xmlFile.ToFileURL} is not exists on your file system or it is ZERO length content!" 
 | 
  | 128 | 
 | 
  | 129 | With New Exception(exMsg) 
 | 
  | 130 | Call App.LogException(.ByRef) 
 | 
  | 131 | 
 | 
  | 132 | If ThrowEx Then 
 | 
  | 133 | Throw .ByRef 
 | 
  | 134 | Else 
 | 
  | 135 | Return Nothing 
 | 
  | 136 | End If 
 | 
  | 137 | End With 
 | 
  | 138 | End If 
 | 
  | 139 | 
 | 
  | 140 | Dim xmlDoc$ = File.ReadAllText(xmlFile, encoding Or UTF8) 
 | 
  | 141 | 
 | 
  | 142 | If Not preprocess Is Nothing Then 
 | 
  | 143 | xmlDoc = preprocess(xmlDoc) 
 | 
  | 144 | End If 
 | 
  | 145 | If stripInvalidsCharacter Then 
 | 
  | 146 | xmlDoc = xmlDoc.StripInvalidCharacters 
 | 
  | 147 | End If 
 | 
  | 148 | 
 | 
  | 149 | Using stream As New StringReader(s:=xmlDoc) 
 | 
  | 150 | Try 
 | 
  | 151 | Dim obj = New XmlSerializer(type).Deserialize(stream) 
 | 
  | 152 | Return obj 
 | 
  | 153 | Catch ex As Exception 
 | 
  | 154 | ex = New Exception(type.FullName, ex) 
 | 
  | 155 | ex = New Exception(xmlFile.ToFileURL, ex) 
 | 
  | 156 | 
 | 
  | 157 | Call App.LogException(ex, MethodBase.GetCurrentMethod.GetFullName) 
 | 
  | 158 | #If DEBUG Then 
 | 
  | 159 | Call ex.PrintException 
 | 
  | 160 | #End If 
 | 
  | 161 | If ThrowEx Then 
 | 
  | 162 | Throw ex 
 | 
  | 163 | Else 
 | 
  | 164 | Return Nothing 
 | 
  | 165 | End If 
 | 
  | 166 | End Try 
 | 
  | 167 | End Using 
 | 
  | 168 | End Function 
 | 
  | 169 | 
 | 
  | 170 | 
 | 
  | 171 | 
 | 
  | 172 | 
 | 
  | 173 | 
 | 
  | 174 | 
 | 
  | 175 | 
 | 
  | 176 | 
 | 
  | 177 | 
 | 
  | 178 | 
 | 
  | 179 | 
 | 
  | 180 | <MethodImpl(MethodImplOptions.AggressiveInlining)> 
 | 
  | 181 | <Extension> Public Function GetXml(Of T)( 
 | 
  | 182 | obj As T, 
 | 
  | 183 | Optional ThrowEx As Boolean = True, 
 | 
  | 184 | Optional xmlEncoding As XmlEncodings = XmlEncodings.UTF16) As String 
 | 
  | 185 | 
 | 
  | 186 | Return GetXml(obj, GetType(T), ThrowEx, xmlEncoding) 
 | 
  | 187 | End Function 
 | 
  | 188 | 
 | 
  | 189 | Public Function GetXml( 
 | 
  | 190 | obj As Object, 
 | 
  | 191 | type As Type, 
 | 
  | 192 | Optional throwEx As Boolean = True, 
 | 
  | 193 | Optional xmlEncoding As XmlEncodings = XmlEncodings.UTF16) As String 
 | 
  | 194 | 
 | 
  | 195 | Try 
 | 
  | 196 | 
 | 
  | 197 | If xmlEncoding = XmlEncodings.UTF8 Then 
 | 
  | 198 | 
 | 
  | 199 | 
 | 
  | 200 | Dim stream As New MemoryStream() 
 | 
  | 201 | 
 | 
  | 202 | Call WriteXML(obj, type, stream, xmlEncoding) 
 | 
  | 203 | 
 | 
  | 204 | 
 | 
  | 205 | Dim result As String = Encoding.UTF8.GetString(stream.ToArray()) 
 | 
  | 206 | Return result 
 | 
  | 207 | Else 
 | 
  | 208 | Dim sBuilder As New StringBuilder(1024) 
 | 
  | 209 | Using StreamWriter As New StringWriter(sb:=sBuilder) 
 | 
  | 210 | Call (New XmlSerializer(type)).Serialize(StreamWriter, obj) 
 | 
  | 211 | Return sBuilder.ToString 
 | 
  | 212 | End Using 
 | 
  | 213 | End If 
 | 
  | 214 | 
 | 
  | 215 | Catch ex As Exception 
 | 
  | 216 | ex = New Exception(type.ToString, ex) 
 | 
  | 217 | Call App.LogException(ex) 
 | 
  | 218 | 
 | 
  | 219 | #If DEBUG Then 
 | 
  | 220 | Call ex.PrintException 
 | 
  | 221 | #End If 
 | 
  | 222 | 
 | 
  | 223 | If throwEx Then 
 | 
  | 224 | Throw ex 
 | 
  | 225 | Else 
 | 
  | 226 | Return Nothing 
 | 
  | 227 | End If 
 | 
  | 228 | End Try 
 | 
  | 229 | End Function 
 | 
  | 230 | 
 | 
  | 231 | <MethodImpl(MethodImplOptions.AggressiveInlining)> 
 | 
  | 232 | <Extension> Public Function CodePage(xmlEncoding As XmlEncodings) As Encoding 
 | 
  | 233 | Select Case xmlEncoding 
 | 
  | 234 | Case XmlEncodings.GB2312 
 | 
  | 235 | Return Encodings.GB2312.CodePage 
 | 
  | 236 | Case XmlEncodings.UTF8 
 | 
  | 237 | Return UTF8WithoutBOM 
 | 
  | 238 | Case Else 
 | 
  | 239 | Return Encodings.UTF16.CodePage 
 | 
  | 240 | End Select 
 | 
  | 241 | End Function 
 | 
  | 242 | 
 | 
  | 243 | 
 | 
  | 244 | 写入的文本文件的编码格式和XML的编码格式应该是一致的 
 | 
  | 245 | 
 | 
  | 246 | 
 | 
  | 247 | <param name="type"></param> 
 | 
  | 248 | <param name="out"></param> 
 | 
  | 249 | <param name="encoding"></param> 
 | 
  | 250 | Public Sub WriteXML(obj As Object, type As Type, ByRef out As Stream, encoding As XmlEncodings) 
 | 
  | 251 | Dim serializer As New XmlSerializer(type) 
 | 
  | 252 | 
 | 
  | 253 | 
 | 
  | 254 | Dim xtWriter As New XmlTextWriter(out, encoding.CodePage) 
 | 
  | 255 | 
 | 
  | 256 | Call serializer.Serialize(xtWriter, obj) 
 | 
  | 257 | Call xtWriter.Flush() 
 | 
  | 258 | End Sub 
 | 
  | 259 | 
 | 
  | 260 | 
 | 
  | 261 | Save the object as the XML document. 
 | 
  | 262 | 
 | 
  | 263 | 
 | 
  | 264 | 
 | 
  | 265 | <param name="saveXml"></param> 
 | 
  | 266 | </param> 
 | 
  | 267 | <param name="encoding">VB.NET的XML文件的默认编码格式为``utf-16``</param> 
 | 
  | 268 | 
 | 
  | 269 | <Extension> Public Function SaveAsXml(Of T As Class)( 
 | 
  | 270 | obj As T, 
 | 
  | 271 | saveXml As String, 
 | 
  | 272 | Optional throwEx As Boolean = True, 
 | 
  | 273 | Optional encoding As Encodings = Encodings.UTF16, 
 | 
  | 274 | <CallerMemberName> Optional caller As String = "") As Boolean 
 | 
  | 275 | Try 
 | 
  | 276 | Return obj _ 
 | 
  | 277 | .GetXml(ThrowEx:=throwEx, xmlEncoding:=encoding) _ 
 | 
  | 278 | .SaveTo(saveXml, encoding.CodePage, throwEx:=throwEx) 
 | 
  | 279 | Catch ex As Exception 
 | 
  | 280 | ex = New Exception(caller, ex) 
 | 
  | 281 | 
 | 
  | 282 | If throwEx Then 
 | 
  | 283 | Throw ex 
 | 
  | 284 | Else 
 | 
  | 285 | Call App.LogException(ex) 
 | 
  | 286 | Call ex.PrintException 
 | 
  | 287 | Return False 
 | 
  | 288 | End If 
 | 
  | 289 | End Try 
 | 
  | 290 | End Function 
 | 
  | 291 | 
 | 
  | 292 | <ExportAPI("Xml.GetAttribute")> 
 | 
  | 293 | <Extension> Public Function GetXmlAttrValue(str As String, Name As String) As String 
 | 
  | 294 | Dim m As Match = r.Match(str, Name & "\s*=\s*(("".+?"")|[^ ]*)") 
 | 
  | 295 | 
 | 
  | 296 | If Not m.Success Then 
 | 
  | 297 | Return "" 
 | 
  | 298 | Else 
 | 
  | 299 | str = m.Value.GetTagValue("=", trim:=True).Value 
 | 
  | 300 | End If 
 | 
  | 301 | 
 | 
  | 302 | If str.First = """"c AndAlso str.Last = """"c Then 
 | 
  | 303 | str = Mid(str, 2, Len(str) - 2) 
 | 
  | 304 | End If 
 | 
  | 305 | 
 | 
  | 306 | Return str 
 | 
  | 307 | End Function 
 | 
  | 308 | 
 | 
  | 309 | 
 | 
  | 310 | Generate a specific type object from a xml document stream.(使用一个XML文本内容创建一个XML映射对象) 
 | 
  | 311 | 
 | 
  | 312 | 
 | 
  | 313 | <param name="Xml">This parameter value is the document text of the xml file, not the file path of the xml file.(是Xml文件的文件内容而非文件路径)</param> 
 | 
  | 314 | Should this program throw the exception when the xml deserialization error happens? 
 | 
  | 315 | if False then this function will returns a null value instead of throw exception. 
 | 
  | 316 | (在进行Xml反序列化的时候是否抛出错误,默认抛出错误,否则返回一个空对象)</param> 
 | 
  | 317 | 
 | 
  | 318 | 
 | 
  | 319 | <Extension> Public Function LoadFromXml(Of T)(xml$, Optional throwEx As Boolean = True) As T 
 | 
  | 320 | Using Stream As New StringReader(s:=xml) 
 | 
  | 321 | Try 
 | 
  | 322 | Dim type As Type = GetType(T) 
 | 
  | 323 | Dim o As Object = New XmlSerializer(type).Deserialize(Stream) 
 | 
  | 324 | Return DirectCast(o, T) 
 | 
  | 325 | Catch ex As Exception 
 | 
  | 326 | Dim curMethod As String = MethodBase.GetCurrentMethod.GetFullName 
 | 
  | 327 | 
 | 
  | 328 | If Len(xml) <= 4096 * 100 Then 
 | 
  | 329 | ex = New Exception(xml, ex) 
 | 
  | 330 | End If 
 | 
  | 331 | 
 | 
  | 332 | App.LogException(ex, curMethod) 
 | 
  | 333 | 
 | 
  | 334 | If throwEx Then 
 | 
  | 335 | Throw ex 
 | 
  | 336 | Else 
 | 
  | 337 | Return Nothing 
 | 
  | 338 | End If 
 | 
  | 339 | End Try 
 | 
  | 340 | End Using 
 | 
  | 341 | End Function 
 | 
  | 342 | 
 | 
  | 343 | <ExportAPI("Xml.CreateObject")> 
 | 
  | 344 | <Extension> Public Function CreateObjectFromXml(Xml As StringBuilder, typeInfo As Type) As Object 
 | 
  | 345 | Dim doc As String = Xml.ToString 
 | 
  | 346 | 
 | 
  | 347 | Using Stream As New StringReader(doc) 
 | 
  | 348 | Try 
 | 
  | 349 | Dim obj As Object = New XmlSerializer(typeInfo).Deserialize(Stream) 
 | 
  | 350 | Return obj 
 | 
  | 351 | Catch ex As Exception 
 | 
  | 352 | ex = New Exception(doc, ex) 
 | 
  | 353 | ex = New Exception(typeInfo.FullName, ex) 
 | 
  | 354 | 
 | 
  | 355 | Call App.LogException(ex) 
 | 
  | 356 | 
 | 
  | 357 | Throw ex 
 | 
  | 358 | End Try 
 | 
  | 359 | End Using 
 | 
  | 360 | End Function 
 | 
  | 361 | 
 | 
  | 362 | 
 | 
  | 363 | 使用一个XML文本内容的一个片段创建一个XML映射对象 
 | 
  | 364 | 
 | 
  | 365 | 
 | 
  | 366 | <param name="xml">是Xml文件的文件内容而非文件路径</param> 
 | 
  | 367 | 
 | 
  | 368 | 
 | 
  | 369 | 
 | 
  | 370 | <MethodImpl(MethodImplOptions.AggressiveInlining)> 
 | 
  | 371 | <Extension> Public Function CreateObjectFromXmlFragment(Of T)(xml$, Optional preprocess As Func(Of String, String) = Nothing) As T 
 | 
  | 372 | Dim xmlDoc$ = 
 | 
  | 373 | "<?xml version=""1.0"" encoding=""UTF-8""?>" & 
 | 
  | 374 | ASCII.LF & 
 | 
  | 375 | xml 
 | 
  | 376 | 
 | 
  | 377 | If Not preprocess Is Nothing Then 
 | 
  | 378 | xmlDoc = preprocess(xmlDoc) 
 | 
  | 379 | End If 
 | 
  | 380 | 
 | 
  | 381 | Try 
 | 
  | 382 | Using s As New StringReader(s:=xmlDoc) 
 | 
  | 383 | Return DirectCast(New XmlSerializer(GetType(T)).Deserialize(s), T) 
 | 
  | 384 | End Using 
 | 
  | 385 | Catch ex As Exception 
 | 
  | 386 | Dim root$ = xml.GetBetween("<", ">").Split.First 
 | 
  | 387 | Dim file$ = App.LogErrDIR & "/" & $"{root}-{Path.GetTempFileName.BaseName}.Xml" 
 | 
  | 388 | 
 | 
  | 389 | Call xmlDoc.SaveTo(file) 
 | 
  | 390 | 
 | 
  | 391 | Throw New Exception("Details at file dump: " & file, ex) 
 | 
  | 392 | End Try 
 | 
  | 393 | End Function 
 | 
  | 394 | 
 | 
  | 395 | <Extension> 
 | 
  | 396 | Public Function SetXmlEncoding(xml As String, encoding As XmlEncodings) As String 
 | 
  | 397 | Dim xmlEncoding As String = Text.Xml.XmlDeclaration.XmlEncodingString(encoding) 
 | 
  | 398 | Dim head As String = Regex.Match(xml, XmlDoc.XmlDeclares, RegexICSng).Value 
 | 
  | 399 | Dim enc As String = Regex.Match(head, "encoding=""\S+""", RegexICSng).Value 
 | 
  | 400 | 
 | 
  | 401 | If String.IsNullOrEmpty(enc) Then 
 | 
  | 402 | enc = head.Replace("?>", $" encoding=""{xmlEncoding}""?>") 
 | 
  | 403 | Else 
 | 
  | 404 | enc = head.Replace(enc, $"encoding=""{xmlEncoding}""") 
 | 
  | 405 | End If 
 | 
  | 406 | 
 | 
  | 407 | xml = xml.Replace(head, enc) 
 | 
  | 408 | 
 | 
  | 409 | Return xml 
 | 
  | 410 | End Function 
 | 
  | 411 | 
 | 
  | 412 | <Extension> 
 | 
  | 413 | Public Function SetXmlStandalone(xml As String, standalone As Boolean) As String 
 | 
  | 414 | Dim opt As String = Text.Xml.XmlDeclaration.XmlStandaloneString(standalone) 
 | 
  | 415 | Dim head As String = Regex.Match(xml, XmlDoc.XmlDeclares, RegexICSng).Value 
 | 
  | 416 | Dim enc As String = Regex.Match(head, "standalone=""\S+""", RegexICSng).Value 
 | 
  | 417 | 
 | 
  | 418 | If String.IsNullOrEmpty(enc) Then 
 | 
  | 419 | enc = head.Replace("?>", $" standalone=""{opt}""?>") 
 | 
  | 420 | Else 
 | 
  | 421 | enc = head.Replace(enc, $"standalone=""{opt}""") 
 | 
  | 422 | End If 
 | 
  | 423 | 
 | 
  | 424 | xml = xml.Replace(head, enc) 
 | 
  | 425 | 
 | 
  | 426 | Return xml 
 | 
  | 427 | End Function 
 | 
  | 428 | End Module 
 |