Чтение информации тегов XML в VB.NET
Одно возможное (рабочее) решение:
Private Sub ReadXMLAttributes(ByVal oXML As String)
ReadXMLAttributes(oXML, "mso-infoPathSolution")
End Sub
Private Sub ReadXMLAttributes(ByVal oXML As String, ByVal oTagName As String)
Try
Dim XmlDoc As New Xml.XmlDocument
XmlDoc.LoadXml(oXML)
oFileInfo = New InfoPathDocument
Dim XmlNodes As Xml.XmlNodeList = XmlDoc.GetElementsByTagName(oTagName)
For Each xNode As Xml.XmlNode In XmlNodes
With xNode
oFileInfo.SolutionVersion = .Attributes(InfoPathSolution.solutionVersion).Value
oFileInfo.ProductVersion = .Attributes(InfoPathSolution.productVersion).Value
oFileInfo.PIVersion = .Attributes(InfoPathSolution.PIVersion).Value
oFileInfo.href = .Attributes(InfoPathSolution.href).Value
oFileInfo.name = .Attributes(InfoPathSolution.name).Value
End With
Next
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.OkOnly, "ReadXMLAttributes")
End Try
End Sub
Это работает, но все еще будет страдать от проблемы ниже, если атрибуты переупорядочены. Единственный способ избежать этой проблемы, который я могу придумать, - это жестко закодировать имена атрибутов в моей программе и обработать запись, просматривая проанализированный тег и ища назначенные теги.
ПРИМЕЧАНИЕ: InfoPathDocument - это пользовательский класс, который я создал, ничего сложного:
Public Class InfoPathDocument
Private _sVersion As String
Private _pVersion As String
Private _piVersion As String
Private _href As String
Private _name As String
Public Property SolutionVersion() As String
Get
Return _sVersion
End Get
Set(ByVal value As String)
_sVersion = value
End Set
End Property
Public Property ProductVersion() As String
Get
Return _pVersion
End Get
Set(ByVal value As String)
_pVersion = value
End Set
End Property
Public Property PIVersion() As String
Get
Return _piVersion
End Get
Set(ByVal value As String)
_piVersion = value
End Set
End Property
Public Property href() As String
Get
Return _href
End Get
Set(ByVal value As String)
If value.ToLower.StartsWith("file:///") Then
value = value.Substring(8)
End If
_href = Form1.PathToUNC(URLDecode(value))
End Set
End Property
Public Property name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Sub New()
End Sub
Sub New(ByVal oSolutionVersion As String, ByVal oProductVersion As String, ByVal oPIVersion As String, ByVal oHref As String, ByVal oName As String)
SolutionVersion = oSolutionVersion
ProductVersion = oProductVersion
PIVersion = oPIVersion
href = oHref
name = oName
End Sub
Public Function URLDecode(ByVal StringToDecode As String) As String
Dim TempAns As String = String.Empty
Dim CurChr As Integer = 1
Dim oRet As String = String.Empty
Try
Do Until CurChr - 1 = Len(StringToDecode)
Select Case Mid(StringToDecode, CurChr, 1)
Case "+"
oRet &= " "
Case "%"
oRet &= Chr(Val("&h" & Mid(StringToDecode, CurChr + 1, 2)))
CurChr = CurChr + 2
Case Else
oRet &= Mid(StringToDecode, CurChr, 1)
End Select
CurChr += 1
Loop
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.OkOnly, "URLDecode")
End Try
Return oRet
End Function
End Class
Оригинальный вопрос
Я работаю над проектом, который требует чтения XML-документа, в частности, сохраненной формы из Microsoft InfoPath.
Вот простой пример того, с чем я буду работать вместе с некоторой справочной информацией, которая может быть полезна:
<?xml version="1.0" encoding="UTF-8"?>
<?mso-infoPathSolution solutionVersion="1.0.0.2" productVersion="12.0.0" PIVersion="1.0.0.0" href="file:///C:\Users\darren\Desktop\simple_form.xsn" name="urn:schemas-microsoft-com:office:infopath:simple-form:-myXSD-2009-05-15T14-16-37" ?>
<?mso-application progid="InfoPath.Document" versionProgid="InfoPath.Document.2"?>
<my:myFields xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2009-05-15T14:16:37" xml:lang="en-us">
<my:first_name>John</my:first_name>
<my:last_name>Doe</my:last_name>
</my:myFields>
Моя цель сейчас - извлечь versionID и местоположение формы. Достаточно просто с регулярным выражением:
Dim _doc As New XmlDocument
_doc.Load(_thefile)
Dim oRegex As String = "^solutionVersion=""(?<sVersion>[0-9.]*)"" productVersion=""(?<pVersion>[0-9.]*)"" PIVersion=""(?<piVersion>[0-9.]*)"" href=""(?<href>.*)"" name=""(?<name>.*)""$"
Dim rx As New Regex(oRegex), m As Match = Nothing
For Each section As XmlNode In _doc.ChildNodes
m = rx.Match(section.InnerText.Trim)
If m.Success Then
Dim temp As String = m.Groups("name").Value.Substring(m.Groups("name").Value.ToLower.IndexOf("infopath") + ("infopath").Length + 1)
fileName = temp.Substring(0, temp.LastIndexOf(":"))
fileVersion = m.Groups("sVersion").Value
End If
Next
Единственная проблема, с которой сталкивается это рабочее решение, заключается в том, что схема изменяется в заголовке документа InfoPath... например, версия решения и свойства версии продукта меняются местами (кажется, Microsoft LOVES делает подобные вещи).
Поэтому я решил использовать возможность синтаксического анализа XML в VB.NET, чтобы помочь мне достичь указанных выше результатов, sans-regex.
ChildNode
от _doc
Объект, который содержит информацию, которая мне нужна, но не имеет дочерних узлов:
_doc.ChildNode(1).HasChildNodes = False
Кто-нибудь может мне помочь с этим?
2 ответа
Инструкции по обработке являются частью XML-документа, но их атрибуты не анализируются. Попробуйте этот код:
// Load the original xml...
var xml = new XmlDocument();
xml.Load( _thefile );
// Select out the processing instruction...
var infopathProcessingInstruction = xml.SelectSingleNode( "/processing-instruction()[local-name(.) = \"mso-infoPathSolution\"]" );
// Since the processing instruction does not expose it's attributes, create a new XML document...
var xmlInfoPath = new XmlDocument();
xmlInfoPath.LoadXml("<data " + infopathProcessingInstruction.InnerText + " />");
// Get the data...
var solutionVersion = xmlInfoPath.DocumentElement.GetAttribute("solutionVersion");
var productVersion = xmlInfoPath.DocumentElement.GetAttribute("productVersion");
Проблема в том, что теги, которые вы хотите проанализировать, на самом деле не являются частью XML-документа. Это XML-пролог, содержащий инструкции по обработке. И поэтому они не будут доступны в XmlDocument как элементы.
Моя единственная идея (кроме просмотра документации о том, как можно получить доступ к этим элементам) - переместить только элемент mso-infoPathSolution в собственный элемент XmlDocument после удаления ?> прочь и заменив их на >. Затем вы можете получить доступ к атрибутам независимо от их порядка.