我正在尝试解析 Google 联系人 API 返回的 XML
我制作了一些帮助类来让我对必要的数据进行强类型访问,但似乎无法让它们协同工作。
我创建了一个继承 XDocument 的类 GoogleDocument 和一个继承 XElement 的 GoogleContact
Class GoogleDocument
Inherits XDocument
Dim xnsAtom = XNamespace.Get("http://www.w3.org/2005/Atom")
Sub New()
MyBase.new()
End Sub
Sub New(other As XDocument)
MyBase.New(other)
End Sub
ReadOnly Property Entries As IEnumerable(Of GoogleContact)
Get
Dim feed = Element(xnsAtom + "feed")
Dim ret = New List(Of GoogleContact)
For Each e In feed.Elements(xnsAtom + "entry")
ret.Add(New GoogleContact(e))
Next
Return ret.AsEnumerable
End Get
End Property
End Class
Class GoogleContact
Inherits XElement
Dim xnsGd = XNamespace.Get("http://schemas.google.com/g/2005")
Dim xnsAtom = XNamespace.Get("http://www.w3.org/2005/Atom")
Dim xnsApp = XNamespace.Get("http://www.w3.org/2007/app")
Sub New(other As XElement)
MyBase.new(other)
End Sub
ReadOnly Property ETag As String
Get
Return Attribute(xnsGd + "etag").Value
End Get
End Property
ReadOnly Property ContactID As Integer
Get
Dim uri = Element(xnsAtom + "id").Value
Return uri.Substring(uri.LastIndexOf("/") + 1)
End Get
End Property
ReadOnly Property Edited As DateTime
Get
Return Date.Parse(Element(xnsApp + "edited").Value)
End Get
End Property
End Class
问题:
{<entry....>}
而不是 <entry....>
我不确定这些大括号在这里是什么意思,但很奇怪 我很感激关于这个主题的任何建议
非常感谢你
编辑
这是一个更完整的代码示例,根据 Jon Skeet 的建议进行更改
Imports System.Net
Imports System.Text
Imports System.IO
Imports System.Collections.Specialized
Imports System.Runtime.CompilerServices
Module Module1
Dim GUserName As String
Dim GPassword As String
Sub Main()
Dim authRequest As HttpWebRequest = HttpWebRequest.Create("https://www.google.com/accounts/ClientLogin")
authRequest.KeepAlive = True
authRequest.ContentType = "application/x-www-form-urlencoded"
authRequest.Method = "POST"
Dim encoder = New ASCIIEncoding
Dim encodedData = encoder.GetBytes("Email=" & GUserName & "&Passwd=" & GPassword & "&source=Consultor&service=cp&accountType=HOSTED_OR_GOOGLE")
authRequest.ContentLength = encodedData.Length
Dim requestStream = authRequest.GetRequestStream
requestStream.Write(encodedData, 0, encodedData.Length)
requestStream.Close()
Dim authResponse = authRequest.GetResponse
Dim readStream = New StreamReader(authResponse.GetResponseStream, encoder)
Dim body = readStream.ReadToEnd
Dim tokens = TextCollection(body, "=", Chr(10))
Dim req2 = New GoogleClient(tokens("auth"))
body = req2.GetString("default/full?max-results=5000")
Dim gDoc = New GoogleDocument(XDocument.Parse(body))
Dim dcx = DBEntities()
Dim pers = dcx.Persons
For Each ge In gDoc.Entries
Dim entry = ge
Dim id As String = entry.ContactID
Dim p As Object '= (From x In pers Where x.GoogleCode = id).FirstOrDefault' cant ompile iin this demo
If p Is Nothing Then Exit For
If entry.Edited > p.LastEdit Then
p.GoogleCode = entry.ContactID
dcx.SaveChanges()
Else
Dim updClient = New GoogleClient(tokens("auth"))
updClient.ETag = entry.ETag
Dim updResp = updClient.PutString("http://www.google.com/m8/feeds/contacts/" & GUserName & "/base/" & entry.ContactID, entry.UpdateXml)
End If
Next
End Sub
Class GoogleClient
Inherits WebClient
Property ETag As String
Const UrlStart = "https://www.google.com/m8/feeds/contacts/"
Sub New(AuthToken As String)
Headers.Add("Content-Type", "application/atom+xml; charset=UTF-8")
Headers.Add("User-Agent", "G-Consultor/GDataGAuthRequestFactory-CS-Version=1.9.0.23118--IEnumerable")
Headers.Add("Authorization", "GoogleLogin auth=" & AuthToken)
Headers.Add("GData-Version", "3.0")
End Sub
Function GetString(Path As String) As String
Return DownloadString(UrlStart & Path)
End Function
Public Function PutString(address As String, data As String) As String
If ETag <> "" Then
Headers.Add("Etag", ETag)
Headers.Add("If-Match", ETag)
End If
Return UploadString(address, "PUT", data)
End Function
End Class
Function TextCollection(Text As String, FieldDelimiter As String, Optional RowDelimiter As String = vbCrLf) As NameValueCollection
Text = Text.RightCut(RowDelimiter)
Dim ret = New NameValueCollection
Dim rows = Text.Split(RowDelimiter)
For Each cl In rows
ret.Add(cl.Substring(0, cl.IndexOf(FieldDelimiter)), cl.Substring(cl.IndexOf(FieldDelimiter) + FieldDelimiter.Length))
Next
Return ret
End Function
Class GoogleDocument
Inherits XDocument
Dim xnsAtom = XNamespace.Get("http://www.w3.org/2005/Atom")
Sub New()
MyBase.new()
End Sub
Sub New(other As XDocument)
MyBase.New(other)
End Sub
ReadOnly Property Entries As IEnumerable(Of GoogleContact)
Get
Dim feed = Element(xnsAtom + "feed")
Dim ret = New List(Of GoogleContact)
For Each e In feed.Elements(xnsAtom + "entry")
ret.Add(New GoogleContact(e))
Next
Return ret.AsEnumerable
End Get
End Property
End Class
Function DBEntities() As Object 'really should return my EF data model
Return Nothing
End Function
<Extension()> Function RightCut(value As String, CutString As String) As String
If Right(value, CutString.Length) = CutString Then value = value.Substring(0, value.Length - CutString.Length)
Return value
End Function
Class GoogleContact
Dim xnsGd = XNamespace.Get("http://schemas.google.com/g/2005")
Dim xnsAtom = XNamespace.Get("http://www.w3.org/2005/Atom")
Dim xnsApp = XNamespace.Get("http://www.w3.org/2007/app")
Dim xContact As XElement
Sub New(entry As XElement)
xContact = entry
End Sub
ReadOnly Property ETag As String
Get
Return xContact.Attribute(xnsGd + "etag").Value
End Get
End Property
ReadOnly Property ContactID As Integer
Get
Dim uri = xContact.Element(xnsAtom + "id").Value
Return uri.Substring(uri.LastIndexOf("/") + 1)
End Get
End Property
ReadOnly Property Edited As DateTime
Get
Return Date.Parse(xContact.Element(xnsApp + "edited").Value)
End Get
End Property
ReadOnly Property UpdateXml
Get
Return "<?xml version=""1.0"" encoding=""utf-8""?>" & xContact.ToString
End Get
End Property
Overrides Function ToString() As String
Return xContact.ToString
End Function
End Class
End Module
最佳答案
目前还不完全清楚究竟出了什么问题——如果你在任何地方都指定了正确的命名空间,一切都应该没问题。但是,您不需要在所有地方重复这些名称——您可能希望创建类型为 XName
的共享只读字段。以免打错字。我也会使用来自 String
的隐式转换至 XName
为简单起见。在 C# 中,我会这样写:
private static readonly XNamespace AtomNs = "http://www.w3.org/2005/Atom";
private static readonly XNamespace GoogleDataNs =
"http://schemas.google.com/g/2005";
private static readonly XNamespace AppNs = "http://www.w3.org/2007/app";
// You should work out where to put these, and their visibility
public static readonly XName FeedElementName = AtomNs + "feed";
public static readonly XName EntryElementName = AtomNs + "entry";
public static readonly XName ETagAttributeName = GoogleDataNs + "etag";
// etc
然后你可以在任何地方使用这些“常量”——它们是否有命名空间都没有关系;这最终不会在您的代码中使用,因为您只是适本地引用了“元素名称”或“属性名称”。
一般来说,改进代码的方法:
WebClient
派生, XDocument
或 XElement
.如果没有这里的继承,您的代码会更清晰,因为您可以只创建与您尝试建模的对象相关的成员。 XDocument
并创建联系人集合。例如(再次使用 C#,但 VB 会类似):List<GoogleContact> = document.Root
.Elements(GoogleContact.EntryElementName)
.Select(element => new GoogleContact(element))
.ToList();
关于.net - 继承 xdocument/xelement 命名空间问题(谷歌联系人 API),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9856034/