【问题标题】:Need to parse XML string that's returned from database stored procedure需要解析从数据库存储过程返回的 XML 字符串
【发布时间】:2017-01-27 19:10:59
【问题描述】:

我有一个在字段中返回一些 XML 的存储过程调用。还有其他字段返回 XML,但只返回其中的一个元素。这个新字段将包含多个元素,需要遍历这些元素才能为最终用户显示字符串。

以下是将返回的 XML 示例:

<Superbills>
    <Superbill>
        <SuperBillID>1</SuperBillID>
        <EventDate>2004-03-23T13:24:16</EventDate>
        <ProcCodes>
            <ProcCode>27096</ProcCode>
            <ProcCode>76005</ProcCode>
            <ProcCode>A4550</ProcCode>
            <ProcCode>A4641</ProcCode>
            <ProcCode>J3301</ProcCode>
        </ProcCodes>
    </Superbill>
    <Superbill>
        <SuperBillID>2</SuperBillID>
        <EventDate>2004-03-23T13:24:16</EventDate>
        <ProcCodes>
            <ProcCode>27096</ProcCode>
            <ProcCode>76005</ProcCode>
            <ProcCode>A4550</ProcCode>
            <ProcCode>A4641</ProcCode>
            <ProcCode>J3301</ProcCode>
        </ProcCodes>
    </Superbill>
    <Superbill>
        <SuperBillID>3</SuperBillID>
        <EventDate>2004-03-24T13:24:16</EventDate>
        <ProcCodes>
            <ProcCode>27096</ProcCode>
            <ProcCode>76005</ProcCode>
            <ProcCode>A4550</ProcCode>
            <ProcCode>A4641</ProcCode>
            <ProcCode>J3301</ProcCode>
        </ProcCodes>
    </Superbill>
</Superbills>

我需要能够遍历所有 Superbill 集以输出类似于以下内容的内容:

[EventDate] ([ProcCode], [ProcCode], [ProcCode], [ProcCode], [ProcCode])
[EventDate] ([ProcCode], [ProcCode], [ProcCode], [ProcCode], [ProcCode])

基本上,我需要为 Superbill 集中的每个 ProcCodes 构建一个逗号分隔的字符串,并解析出事件日期为每个构建一个字符串。

我尝试过查看using XmlReader,但这并没有为我提供每个“Superbill”元素的单独行。它最终只给了我一起活动的日期,然后给了我ProcCodes。

感谢您的任何意见。

【问题讨论】:

  • 你试过什么?您是否有一些代码可以说明您在反序列化 xml 时遇到的问题?
  • 添加了使用 xmlreader 的尝试。
  • 使用 XmlDocument.loadXML(strXML)。然后写一个XSL来输出你需要的字段。
  • 或者不使用XSL,使用XmlDocment.loadXML,然后在selectNodes方法中使用类似“//Superbill”的XPath来遍历每一个。
  • XmlReader 用于这样的任务很痛苦。从 XML 创建和 XmlDocument 并使用 XPath 选择元素或创建 XDocument 并使用 Linq2Xml 提取您需要的内容。

标签: asp.net xml vb.net


【解决方案1】:

我采用了 Serializer 方法...

Imports System.IO
Imports System.Text
Imports System.Xml.Serialization

Module Module1
    Sub Main()
        Dim XMLString As String = File.ReadAllText("SuperBills.xml")

        With New XmlSerializer(GetType(Superbills)).Deserialize(New IO.MemoryStream(Encoding.UTF8.GetBytes(XMLString)))
            For Each SuperBill As Superbill In .Superbills
                Debug.Print("{0} ({1})", SuperBill.EventDate.ToShortDateString, Join(SuperBill.ProcCodes, ", "))
            Next
        End With
    End Sub
End Module

<XmlRoot()>
Partial Public Class Superbills
    <XmlElement("Superbill")>
    Public Property Superbills As Superbill()
End Class

Partial Public Class Superbill
    Public Property SuperBillID As Byte
    Public Property EventDate As Date

    <XmlArrayItem("ProcCode")>
    Public Property ProcCodes As String()
End Class

这就是你要找的吗?

3/23/2004 (27096, 76005, A4550, A4641, J3301)
3/23/2004 (27096, 76005, A4550, A4641, J3301)
3/24/2004 (27096, 76005, A4550, A4641, J3301)

【讨论】:

  • 我想是的。我的假设是,我不是从读取文件中获取 XML,而是作为从数据库的存储过程中返回的值。在这种情况下,我可以修改例程以接受字符串参数,然后将该字符串参数用于 Dim XMLString?
  • 我已将其放入我的代码中,但它给了我一个关于 for Each 语句中的 .Superbills 的错误。我在后面的用户控制代码中,所以部分公共类在用户控制页面的部分类中。我不确定在嵌套它们方面需要去哪里。
  • 最后一条评论没关系。我在上面的行上有一个额外的右括号,它把所有东西都扔掉了。谢谢你的例子。
【解决方案2】:

如果您只需要 EventDataProcCode 值,您可以使用 Linq To Xml

Dim doc As XDocument = XDocument.Parse(yourString)

var eventsAndCodes = 
    doc.Descendants("Superbill").
        Select(Function(bill) 
                   Return New With
                   {
                       .EventData = bill.Element("EventDate").Value,
                       .ProcCodes = bill.Descendants("ProcCode").Select(Function(code) code.Value).ToList()
                   }
               End Function)

For Each data in eventsAndCodes
    ' Use values
    data.EventData
    data.ProcCodes
Next

您可以创建自己的类型而不是匿名类型以提高可读性

Public Class EventInfo
    Public Property EventDate As Date
    Public Property ProcCodes As List(Of String)
End Class

以及从XElement检索数据的方法

Public Function CreateEventInfoFromXElement(element As XElement) As EventInfo
    Return New EventInfo With
    {
        .EventData = bill.Element("EventDate").Value,
        .ProcCodes = bill.Descendants("ProcCode").
                          Select(Function(code) code.Value).
                          ToList()
    }
End Function

然后使用它们

Dim doc As XDocument = XDocument.Parse(yourString)
Dim eventsData As IEnumerable(Of EventInfo) = 
    doc.Descendants("Superbill").Select(AddressOf CreateEventInfoFromXElement)

【讨论】:

    【解决方案3】:

    我可以使用 LinqToXml 做到这一点:

    var doc = XElement.Parse("...xml...");
    
    var list = doc.XPathSelectElements("//EventDate")
        .Select(e => DateTime.Parse(e.Value).ToShortDateString() + ", (" +
        string.Join(", ", e.ElementsAfterSelf().First().Elements().Select(e2 => e2.Value)) +
        ")").ToList();
    

    转换成VB:

    Dim doc as XElement = XElement.Parse("...xml...")
    
    Dim list as List(of String) = doc.XPathSelectElements("//EventDate").
        Select(Function(e) DateTime.Parse(e.Value).ToShortDateString & 
        ", (" & String.Join(", ", e.ElementsAfterSelf.First.Elements.
        Select(Function(e2) e2.Value)) & ")").ToList
    

    它不是超级漂亮,但它确实有效。它在文档中搜索所有 EventDate 元素,将它们解析为日期,并输出 ShortDate 格式,然后获取下一个兄弟元素中的所有元素并用逗号连接它们的值。它确实假定ProcCode 元素将始终紧跟在EventDate 之后,如果不是则将失败。如果这不符合您的要求,我可以将其更新为更具弹性。

    它产生一个字符串列表,每个EventDate一个,格式如下:

    2004 年 3 月 23 日,(27096、76005、A4550、A4641、J3301)
    2004 年 3 月 23 日,(27096、76005、A4550、A4641、J3301)
    2004 年 3 月 24 日,(27096、76005、A4550、A4641、J3301)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-06
      • 2016-05-07
      • 2017-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-19
      相关资源
      最近更新 更多