Измельчение XML в VB6 / найти максимальное значение атрибута - PullRequest
0 голосов
/ 28 октября 2018

Я новичок в SO - надеюсь, я отправлю это в нужном месте.

В качестве обновления моего поста ниже я нашел один из способов получить часть городаадрес.Мне действительно не нужно максимальное значение, как предложено в моем первоначальном посте;Мне просто нужно последнее значение, потому что значения «xyz: sequenceNumber» всегда, ну, в последовательности.Итак, я попробовал это:

tmpCity = xNode.selectSingleNode("//abc:Person//xyz:Region").previousSibling.Text

, и это похоже на работу, так как я имею дело с хорошо отформатированными файлами .xml, в которых предыдущая строка xyz: Region всегда является последней строкой xyz: AddressText, содержащейГородская ценность, которую я ищу.Я все еще буду благодарен за любые комментарии, потому что я остаюсь в неведении относительно того, является ли это (и код ниже) даже отдаленно эффективным.У меня много больших XML-файлов, поэтому эффективность имеет значение.

Мне нужно работать с устаревшим кодом VB6, который содержит подпрограмму рекурсивного уничтожения XML.Я знаком с VB6, но я не понимаю эту подпрограмму.Я вставил часть кода ниже.Я надеюсь, что кто-то может подсказать мне некоторые подробные справочные материалы для чтения, которые помогут мне понять, как работают аспекты обработки XML этой подпрограммы, чтобы я мог поддерживать и изменять его.Я также вставил ниже [sanitized] образец выдержки из двух файлов XML, с которыми мне нужно работать.Одна проблема заключается в том, что часть адреса City хранится в последнем из перечисленных атрибутов.Чтобы получить Город, мне нужно извлечь текст из атрибута с максимальным значением xyz: sequenceNumber.У SO много постов с примерами того, как получить атрибут наибольшего значения, но я не могу заставить их работать в этой подпрограмме.Как правило, они, похоже, используют либо функцию max () - на что VB6 жалуется, когда я пытаюсь использовать ее в этой подпрограмме;или они используют что-то вроде того, что вы видите в фрагменте ниже, но когда я пытаюсь приспособить это, VB6 жалуется на двойное двоеточие ("::").

doc.SelectSingleNode("//Employees/Employee/@Id[not(. <=../preceding-sibling::Employee/@id) and not(. <=../following-sibling::Employee/@Id)]");

Я предполагаю, что примеры, которые я видел, относятся к библиотекам, отличным от того, что доступно в VB6.

Вот пример XML:

<abc:Person>
  <xyz:LicenseNo>1234</xyz:LicenseNo>
  <xyz:Language xyz:languageCode="en">
    <xyz:Name>
      <xyz:Company xyz:languageCode="en">ABC Company Ltd.</xyz:Company>
    </xyz:Name>
    <xyz:AddressCollection>
      <xyz:Address>
        <xyz:SequencedAddress xyz:languageCode="en">
          <xyz:AddressText xyz:sequenceNumber="1">The ABC Building</xyz:AddressText>
          <xyz:AddressText xyz:sequenceNumber="2">123 Main Street</xyz:AddressText>
          <xyz:AddressText xyz:sequenceNumber="3">3rd Floor</xyz:AddressText>
          <xyz:AddressText xyz:sequenceNumber="4">Tampa</xyz:AddressText>
          <xyz:Region xyz:RegionCategory=“State”>FL</xyz:Region>
          <xyz:CountryCode>US</xyz:CountryCode>
          <xyz:ZipCode>33607</xyz:ZipCode>
        </xyz:SequencedAddress>
      </xyz:Address>
    </xyz:AddressCollection>
  </xyz:Language>
</abc:Person>
<abc:Person>
  <xyz:LicenseNo>567</xyz:LicenseNo>
  <xyz:Language xyz:languageCode="en">
    <xyz:Name>
      <xyz:Company xyz:languageCode="en">XYZ Industries Ltd.</xyz:Company>
    </xyz:Name>
    <xyz:AddressCollection>
      <xyz:Address>
        <xyz:SequencedAddress xyz:languageCode="en">
          <xyz:AddressText xyz:sequenceNumber="1">XYZ Factory Plaza</xyz:AddressText>
          <xyz:AddressText xyz:sequenceNumber="2">678 Elm Street</xyz:AddressText>
          <xyz:AddressText xyz:sequenceNumber="3">Orlando</xyz:AddressText>
          <xyz:Region xyz:RegionCategory=“State”>FL</xyz:Region>
          <xyz:CountryCode>US</xyz:CountryCode>
          <xyz:ZipCode>32814</xyz:ZipCode>
        </xyz:SequencedAddress>
      </xyz:Address>
    </xyz:AddressCollection>
  </xyz:Language>
</abc:Person>

Вот часть кода:

Public Sub ShredXML(ByRef Nodes As MSXML2.IXMLDOMNodeList)
Dim xNode As MSXML2.IXMLDOMNode

    For Each xNode In Nodes
            If xNode.nodeType = NODE_ELEMENT Then
                If xNode.nodeName = "abc:Person" Then
                tmpCompany = xNode.selectSingleNode("//abc:Person//xyz:Company").Text
                tmpLicenseNo = xNode.selectSingleNode("//abc:Person//xyz:LicenseNo").Text
                tmpLanguage = xNode.selectSingleNode("//abc:Person//xyz:Language").Attributes.getNamedItem("xyz:languageCode").Text
                tmpRegion = xNode.selectSingleNode("//abc:Person//xyz:Region").Text
                tmpCountryCode = xNode.selectSingleNode("//abc:Person//xyz:CountryCode").Text
                tmpZipCode = xNode.selectSingleNode("//abc:Person//xyz:ZipCode").Text

‘ database insert code omitted

                End If
            End If

        If xNode.hasChildNodes Then
            ShredXML xNode.childNodes
        End If

   Next xNode

1 Ответ

0 голосов
/ 31 октября 2018

Я взял ваш образец XML-фрагмента, исправил ошибки (использовались неправильные кавычки, “State” вместо "State"), затем поместил его в узел документа:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<doc xmlns:abc="urn:abc" xmlns:xyz="urn:xyz">
:
</doc>

Сохранил это как sample.xml и запустил этот код:

Option Explicit

Private Sub WriteLine(Optional ByVal Text As String)
    With Text1
        .SelStart = &H7FFF 'End.
        If Len(Text) > 0 Then .SelText = Text
        .SelText = vbNewLine
    End With
End Sub

Private Sub Form_Load()
    Dim ParseSuccess As Boolean
    Dim Element1 As MSXML2.IXMLDOMElement
    Dim Element2 As MSXML2.IXMLDOMElement
    Dim LicenseNo As String
    Dim Company As String
    Dim Language As String
    Dim Region As String
    Dim CountryCode As String
    Dim ZipCode As String
    Dim MaxSeqVal As Long
    Dim MaxSeqElement As MSXML2.IXMLDOMElement
    Dim SeqVal As Long
    Dim City As String

    With New MSXML2.DOMDocument60
        ParseSuccess = .Load(App.Path & "\sample.xml")
        WriteLine "Parse success = " & CStr(ParseSuccess)
        If ParseSuccess Then
            WriteLine
            For Each Element1 In .getElementsByTagName("abc:Person")
                With Element1
                    LicenseNo = .getElementsByTagName("xyz:LicenseNo")(0).Text
                    Company = .getElementsByTagName("xyz:Company")(0).Text
                    Set Element2 = .getElementsByTagName("xyz:Language")(0)
                    Language = Element2.getAttribute("xyz:languageCode")
                    Region = .getElementsByTagName("xyz:Region")(0).Text
                    CountryCode = .getElementsByTagName("xyz:CountryCode")(0).Text
                    ZipCode = .getElementsByTagName("xyz:ZipCode")(0).Text
                    MaxSeqVal = -1
                    For Each Element2 In .getElementsByTagName("xyz:AddressText")
                        SeqVal = CLng(Element2.getAttribute("xyz:sequenceNumber"))
                        If SeqVal > MaxSeqVal Then
                            MaxSeqVal = SeqVal
                            Set MaxSeqElement = Element2
                        End If
                    Next
                    City = MaxSeqElement.Text
                End With
                WriteLine LicenseNo
                WriteLine Company
                WriteLine Language
                WriteLine Region
                WriteLine CountryCode
                WriteLine ZipCode
                WriteLine City
                WriteLine
            Next
        End If
    End With
End Sub

Обратите внимание, что интерфейсы Node и Element имеют разные члены (свойства и методы), поэтому здесь используются Element1 и Element2.Это позволяет нам взять Node и запросить его более полезный интерфейс Element.

Кажется, что работает нормально:

Parse success = True

1234
ABC Company Ltd.
en
FL
US
33607
Tampa

567
XYZ Industries Ltd.
en
FL
US
32814
Orlando

Насколько я знаю, MSXML не поддерживает XPath 2, поэтомуоперация "max" не поддерживается.

...