При удалении узла XML DOM удаляются все его узлы.

Мне нужно обрезать XML-документ, удалив некоторые узлы. Для этого у меня есть следующая функция VBA, которая вызывается с помощью

  • списки = XMLOutput.documentelement
  • tagfound = полный путь (//Заголовок/Элемент/Подэлемент/...)

Вот код:

Function RemoveNode(lists, tagfound)
    Dim nodefound As Object
    Set nodefound = lists.selectSingleNode(tagfound)
    If nodefound Is Nothing Then Exit Function
    nodeToBeRemoved = nodefound.basename
    Set x = nodefound.parentnode
    For Each listnode In x.childnodes
        If listnode.basename = nodeToBeRemoved Then
            x.removechild (listnode)
        End If
    Next listnode
End Function

Я пробовал другие решения, более элегантные, такие как одна строка кода, но ВСЕ приводят к одному и тому же результату: если мне нужно удалить дочерний элемент, который является последним дочерним элементом его родителя, все его братья и сестры также удаляются. Я пытался сохранить документ после любого удаления, но безрезультатно. Любые подсказки? Чтобы было понятнее, далее следует мой вклад. Для каждого XML-тега логическое значение говорит мне, должен ли я сохранить его или удалить из XML-дерева.

XMLTag ToBeCoded Заголовок TRUE Заголовок/Организация TRUE Заголовок/Организация/BaseData TRUE Заголовок/Организация/BaseData/НДС TRUE Заголовок/Организация/BaseData/НДС/Страна ИСТИНА Заголовок/Организация/BaseData/НДС/Код ИСТИНА Заголовок/Организация/BaseData/SocialSecurity FALSE Заголовок/Организация/BaseData/PersonalData TRUE Заголовок/Организация/BaseData/PersonalData/Имя организации TRUE Заголовок/Организация/BaseData/PersonalData/PersonalName FALSE Заголовок/Организация/BaseData/PersonalData/FamilyName FALSE Заголовок/Организация/BaseData/PersonalData/Title FALSE Header/ Организация/BaseData/PersonalData/Code FALSE Заголовок/Организация/BaseData/ProfessionalLedger FALSE Заголовок/Организация/BaseData/ContyOfLedger FALSE Заголовок/Организация/BaseData/EnrollmentNumber FALSE Заголовок/Организация/BaseData/Date FALSE Заголовок/Организация/BaseData/IRSType FALSE Заголовок/ Организация/Местоположение TRUE Заголовок/Организация/Местоположение/Адрес TRUE Заголовок/Организация/Местоположение/StreetNumber TRUE Заголовок/Организация/Местоположение/ZIP TRUE Заголовок/Организация/Местоположение/Город TRUE Заголовок/Организация/Местоположение/Округ TRUE Заголовок/Организация/Местоположение/Страна TRUE

..и вот что я получаю:

<Header>
<Organisation>
   <BaseData>
   <VAT></VAT>
     <PersonalData>
     </PersonalData>
  </BaseData>
  <Location>
    <Address>any street name</Address>
    <StreetNumber>any street number</StreetNumber>
    <ZIP>any ZIP code</ZIP>
    <City>any City</City>
    <County>any County</County>
    <Country>any Country</Country>
   </Location>

Легко видеть, что я не получаю никаких полей для тега PersonalData, в то время как я должен был удалить все дочерние элементы, кроме OrganizationName, которое оказалось первым дочерним элементом. Кроме того, BaseData/VAT/Country и BaseData/VAT/Code отсутствуют (родительский элемент НДС есть, но пустой).


person Facan    schedule 20.07.2018    source источник
comment
почему ты зацикливаешься? nodefound.parentnode.removechild nodefound достаточно.   -  person S Meaden    schedule 20.07.2018
comment
Как я уже сказал, я пробовал несколько разных способов. Мой первый код был именно тем, что вы предложили. Те же результаты. Я зациклился, надеясь, что изменение имен (например, x вместо nodefound.parentnode) решит мою проблему волшебным образом...   -  person Facan    schedule 20.07.2018
comment
Любой XML, чтобы пойти с вышеизложенным вместе с ожидаемым результатом?   -  person QHarr    schedule 21.07.2018
comment
x является родителем. listnode проходит через каждый x.childnodes (поэтому listnode - это каждый дочерний элемент, по одному). Поскольку x является родителем, когда вы говорите x.removechild, вы удаляете всех дочерних элементов родителя (также известных как братья и сестры). Вам нужно удалить listnode, а не x. Кроме того, я бы посоветовал вам объявить все ваши переменные (а еще лучше использовать Option Explicit в верхней части модуля, чтобы обеспечить правильное объявление и обработку).   -  person ashleedawg    schedule 21.07.2018
comment
Большое спасибо за ваши добрые предложения. Однако есть кое-что, чего я не понимаю (извините за мою тупость): поскольку я не могу удалить узел напрямую, а только как дочерний элемент, я должен использовать x.removechild, обращаясь к соответствующему удаляемому дочернему элементу. И я предположил, что, будучи родительским элементом x и удаляемым узлом списка, x.removechild(listnode) выполнит эту работу. Где я не прав? А что касается объявления переменных, то то, что я опубликовал, является отредактированным отрывком фактического (длинного) кода, где объявления сделаны правильно, я обещаю.   -  person Facan    schedule 21.07.2018
comment
Я добавил исходный файл, который говорит мне, какие теги оставить, а какие удалить, и результирующий XML-файл, в котором есть не все, что нужно было сохранить.   -  person Facan    schedule 21.07.2018


Ответы (1)


Следующий код демонстрирует удаление узла Zip.

Option Explicit

Sub TestRemoveNode()

    Dim dom As MSXML2.DOMDocument60
    Set dom = New MSXML2.DOMDocument60

    dom.LoadXML "<Header><Organisation><BaseData><VAT></VAT><PersonalData></PersonalData></BaseData><Location>" & _
    "<Address>any street name</Address><StreetNumber>any street number</StreetNumber><ZIP>any ZIP code</ZIP>" & _
    "<City>any City</City><County>any County</County><Country>any Country</Country></Location></Organisation></Header>"
    Debug.Assert dom.parseError = 0

    '* find a node
    Dim xmlZip As MSXML2.IXMLDOMNode
    Set xmlZip = dom.SelectSingleNode("//ZIP")

    xmlZip.ParentNode.RemoveChild xmlZip

    Debug.Assert dom.XML = "<Header><Organisation><BaseData><VAT></VAT><PersonalData></PersonalData></BaseData><Location>" & _
    "<Address>any street name</Address><StreetNumber>any street number</StreetNumber>" & _
    "<City>any City</City><County>any County</County><Country>any Country</Country></Location></Organisation></Header>" & vbNewLine

End Sub
person S Meaden    schedule 21.07.2018