【问题标题】:Reading XML in VB在 VB 中读取 XML
【发布时间】:2014-10-17 14:46:30
【问题描述】:

我正在尝试在我的应用程序中读取 iTunes 音乐库 XML,但是我不知道如何执行此操作,我想做的是搜索特定的曲目名称和指定键,例如“艺术家”、“专辑”等。是的,我知道如何使用 iTunes COM,但有些曲目信息无法通过它访问,例如如果曲目是“显式”,则有一个附加键

<key>Explicit</key><true/>

我想要做的是搜索一个特定的轨道名称并检查它的轨道是否有一个明确的键。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Major Version</key><integer>1</integer>
    <key>Minor Version</key><integer>1</integer>
    <key>Date</key><date>2014-08-24T05:21:40Z</date>
    <key>Application Version</key><string>11.3.1</string>
    <key>Features</key><integer>5</integer>
    <key>Show Content Ratings</key><true/>
    <key>Music Folder</key><string>file://localhost/C:/Users/Mon%20Tolentino/Music/iTunes/iTunes%20Media/</string>
    <key>Library Persistent ID</key><string>15CDC06EC711077D</string>
    <key>Tracks</key>
    <dict>
        <key>766</key>
        <dict>
            <key>Track ID</key><integer>766</integer>
            <key>Name</key><string>Say Something</string>
            <key>Artist</key><string>A Great Big World</string>
            <key>Album Artist</key><string>A Great Big World</string>
            <key>Composer</key><string>Ian Axel, Chad Vaccarino, Mike Campbell</string>
            <key>Album</key><string>Is There Anybody Out There?</string>
            <key>Grouping</key><string>Indie</string>
            <key>Genre</key><string>Pop</string>
            <key>Kind</key><string>AAC audio file</string>
            <key>Size</key><integer>8639959</integer>
            <key>Total Time</key><integer>233289</integer>
            <key>Disc Number</key><integer>1</integer>
            <key>Disc Count</key><integer>1</integer>
            <key>Track Number</key><integer>5</integer>
            <key>Track Count</key><integer>13</integer>
            <key>Year</key><integer>2013</integer>
            <key>BPM</key><integer>94</integer>
            <key>Date Modified</key><date>2014-05-25T15:58:35Z</date>
            <key>Date Added</key><date>2014-05-18T10:09:13Z</date>
            <key>Bit Rate</key><integer>256</integer>
            <key>Sample Rate</key><integer>44100</integer>
            <key>Play Count</key><integer>33</integer>
            <key>Play Date</key><integer>3491589574</integer>
            <key>Play Date UTC</key><date>2014-08-22T13:59:34Z</date>
            <key>Skip Count</key><integer>7</integer>
            <key>Skip Date</key><date>2014-08-15T15:15:43Z</date>
            <key>Release Date</key><date>2013-11-04T12:00:00Z</date>
            <key>Rating</key><integer>60</integer>
            <key>Album Rating</key><integer>60</integer>
            <key>Album Rating Computed</key><true/>
            <key>Artwork Count</key><integer>1</integer>
            <key>Sort Album Artist</key><string>A Great Big World</string>
            <key>Sort Artist</key><string>A Great Big World</string>
            <key>Persistent ID</key><string>50A143EFFA8BEA97</string>
            <key>Track Type</key><string>File</string>
            <key>Location</key><string>file://localhost/C:/Users/Mon%20Tolentino/Music/iTunes/iTunes%20Media/Music/A%20Great%20Big%20World/Is%20There%20Anybody%20Out%20There_/05%20Say%20Something.m4a</string>
            <key>File Folder Count</key><integer>5</integer>
            <key>Library Folder Count</key><integer>1</integer>
        </dict>

我在网上找到了这个:

    Dim itunesLib As XElement = XElement.Load("xmllocation")

    Dim itunesPlaylists = From key In itunesLib...<key> Where key.Value = "Name"
                          Select key.ElementsAfterSelf("string").Value

    List1.ItemsSource = itunesPlaylists

但它只在列表框中列出了我所有的曲目,谁能帮帮我。

【问题讨论】:

    标签: c# xml vb.net itunes


    【解决方案1】:

    .net 中有几种查询 XML 文档的方法 你可以使用直接 DOM 查询

    例如:

    XmlDOcument doc=new XmlDOcument();
    doc.LoadXml("your raw xml");
    
    var plist=doc.DOcumentElement.Children[0]; //my plist
    var rootDict=plist.Children[0]; //my root dict
    //..
    //and so on 
    

    在此处阅读有关 .NET XML DOM API 的信息

    http://msdn.microsoft.com/en-us/magazine/cc302158.aspx

    您也可以使用 Xml 查询语言:Xpath

    http://www.codeproject.com/Articles/9494/Manipulate-XML-data-with-XPath-and-XmlDocument-C

    【讨论】:

      【解决方案2】:

      哇,这是我见过的最糟糕的 XML。我对不得不忍受这一点表示哀悼。

      我很想先将它们解析为(可能是延迟的)具体类的集合,然后 .Where 那些找到您正在寻找的类。

      我最初用 C# 编写了所有这些代码,因为我实际上并不真正了解 VB,然后使用在线工具对其进行了转换,因此请告诉我是否存在问题或其中任何一个不是最佳实践。不过,它应该传达工作流程的要点,这才是重点。

      那么,我先写一个类:

      Public Class Track
          Public Property Name() As String
              Get
                  Return m_Name
              End Get
              Set
                  m_Name = Value
              End Set
          End Property
          Private m_Name As String
          Public Property Explicit() As Boolean
              Get
                  Return m_Explicit
              End Get
              Set
                  m_Explicit = Value
              End Set
          End Property
          Private m_Explicit As Boolean
      End Class
      

      然后我会编写一个方法来获取 &lt;dict&gt; 元素中任何键的值

      Private Function GetValue(Of T)(dict As XElement, key As String) As T
          Dim element = dict.Elements("key").FirstOrDefault(Function(c) String.Equals(DirectCast(c, String), key))
      
          If element Is Nothing OrElse element.NextNode Is Nothing Then
              Return Nothing
          End If
      
          element = element.NextNode
      
          If T = GetType(Boolean) Then
              Return element.Name = "true"
          Else
              Return DirectCast(element, T)
          End If
      End Function
      

      然后将 XML 解析为该类:

      Dim root = XElement.Load(path)
      
      root = root.Element("dict")
      
      Dim tracks = root.Elements("key").First(Function(c) DirectCast(c, String) = "Tracks").NextNode.Elements("dict")
      
      Dim parsedTracks As IEnumerable(Of Track) = tracks.[Select](Function(c) New Track() With { _
          Key .Name = GetValue(Of String)(c, "Name"), _
          Key .Explicit = GetValue(Of Boolean)(c, "Explicit") _
      })
      

      然后您可以轻松地对此进行查询:

      Return parsedTracks.First(Function(c) c.Name = desiredTrackName).Explicit
      

      我敢肯定,您会想要添加大量错误处理,但这应该传达出一种好方法的要点。你可能想也可能不想在那里打一个.ToArray() 电话。这真的取决于你如何使用它。就目前而言,这将每次调用仅循环一次(因此“延迟”),因此如果您不经常进行搜索,那就太好了。但是你可能想.ToArray() 它,这样它就会全部加载到内存中,并且如果你正在做更多的调用,它已经被解析了。

      【讨论】:

      • 哇。我认为这是一个 :O 但我不知道如何使用它,我才刚刚开始学习东西。你能给我寄一份样品吗?但是谢谢!!!
      • @MonTolentino 有什么错误?除了在这里回答问题之外,我一生中从未写过任何 VB,但我敢打赌,我可以帮助您解决这些问题。
      • 如果您可以提供一个示例 zip 解决方案,我想我可以自己将其转换为 VB。我的问题是我不怎么把你所有的代码放在一起。再次感谢!我还是不能用它
      • @MonTolentino 我不能说我真的明白你在找什么。这里的所有代码块(或者更确切地说,主要是因为最后两个是相关的)位于不同的位置。第一个应该有一个类,第二个可以去任何你想要的地方,第三个应该去任何你想要解析文件的地方......
      • @har07 给出了我想要的代码,以及我将如何使用它。非常感谢您的帮助,我已经搜索了将近 5 个月。最后。非常感谢你们
      【解决方案3】:

      “我想要做的是搜索特定的轨道名称并检查它的轨道是否有明确的键。”

      您可以使用 LINQ to XML 表达式来检查特定轨道是否是明确的,例如:

      Dim xml As XElement = XElement.Load("xmllocation")
      Dim trackName = "Say Something"
      Dim query = From d In xml...<dict>
                  Where d.Elements("key").Any(Function(name) name.Value = "Name" _
                                                  AndAlso (CType(name.NextNode, XElement).Value = trackName)) _
                        And d.Elements("key").Any(Function(exp) exp.Value = "Explicit" _
                                                   AndAlso (CType(exp.NextNode, XElement).Name = "true"))
      Dim isExplicit As Boolean = query.Any()
      

      或使用与上述 LINQ 等效的 XPath 表达式:

      Dim xpath As String = String.Format("//dict[key[.='Name' and following-sibling::string='{0}'] and key[.='Explicit' and following-sibling::true]]", trackName)
      Dim isExplicit As Boolean = xml.XPathSelectElements(xpath).Any()
      

      更新:

      如果您需要检查除了曲目之外的艺术家姓名,您可以在WHERE 子句中添加另一个过滤器,如下所示:

      Where ....
            And d.Elements("key").Any(Function(artist) artist.Value = "Artist" _
                                       AndAlso (CType(exp.NextNode, XElement).Value = "artist name"))
            And ...
      

      【讨论】:

      • 哦上帝哦上帝,哦上帝哦上帝,哦上帝。我已经为此工作了将近 5 个月。天啊。天啊。太感谢了!!!!我不知道我该如何帮助您,但非常感谢您,就像我刚才所说的那样,我已经为此工作了将近 5 个月。哦,我的上帝
      • 哇 5 个月!你可能想试试这个库PlistCS。它将帮助您立即将 plist XML 反序列化为 .NET Dictionary 类型的对象(虽然我自己没有尝试过)
      • 还有一个......不要忘记稍后再次关闭你的大写锁定:))
      • 但我只有 1 个问题。在我搜索特定的曲目名称后,我还需要验证曲目艺术家是否是我正在查找的曲目,以防有 2 首曲目具有相同的曲目名称。
      • 我还在发疯!!我怎么能在这里帮助你,如果这对你没有问题,我可以在其他地方添加你。非常感谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-16
      • 2011-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多