XML VBA Объединить родительские узлы с одинаковыми значениями

Рейтинг: 0Ответов: 1Опубликовано: 05.06.2023

столкнулся с проблемой при экспортировании с помощью VBS скрипта xml-файла, структура имеет данный вид:

<?xml version="1.0" encoding="windows-1251"?>
<Documents>   
   <Document>
    <Header>            
        <Number>999</Number>
    </Header>
    <Items>
        <Item>
            <Code>111</Code>
        </Item>
    </Items>
</Document>
<Document>
    <Header>
        <Number>999</Number>
    </Header>
    <Items>
        <Item>
            <Code>222</Code>
        </Item>
    </Items>
</Document>
<Document>
    <Header>
        <Number>999</Number>
    </Header>
    <Items>
        <Item>
            <Code>333</Code>
        </Item>
    </Items>
</Document>

Требуемый вид:

<?xml version="1.0" encoding="windows-1251"?>
<Documents>    
   <Document>
       <Header>         
           <Number>999</Number>
       </Header>
       <Items>
           <Item>
               <Code>111</Code>
           </Item>
           <Item>
               <Code>222</Code>
           </Item>
           <Item>
               <Code>333</Code>
           </Item>
       </Items>
   </Document>
</Documents>

Таких записей должно быть около 3 тысяч, а из-за дублирования количество растянулось до ~7 тысяч. Я не сильно разбираюсь в VBA (начал изучение 3~4 дня назад), поэтому, не найдя аналогов решения, прошу помочь. Параллельно буду смотреть в сторону XSLT, вдруг решение в нем скрывается.

Ответы

▲ 0Принят

Пожалуйста, попробуйте следующий XSLT.

Входной XML

<?xml version="1.0" encoding="windows-1251"?>
<Documents>
    <Document>
        <Header>
            <Number>999</Number>
        </Header>
        <Items>
            <Item>
                <Code>111</Code>
            </Item>
        </Items>
    </Document>
    <Document>
        <Header>
            <Number>999</Number>
        </Header>
        <Items>
            <Item>
                <Code>222</Code>
            </Item>
        </Items>
    </Document>
    <Document>
        <Header>
            <Number>999</Number>
        </Header>
        <Items>
            <Item>
                <Code>333</Code>
            </Item>
        </Items>
    </Document>
    <Document>
        <Header>
            <Number>770</Number>
        </Header>
        <Items>
            <Item>
                <Code>100</Code>
            </Item>
        </Items>
    </Document>
</Documents>

XSLT 1.0

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" encoding="windows-1251"/>
    <xsl:strip-space elements="*"/>

    <xsl:key name="DocumentByNumberIndex" match="Document" use="Header/Number"/>

    <xsl:template match="Documents">
        <xsl:copy>
            <xsl:for-each select="Document[generate-id(.) = generate-id(key('DocumentByNumberIndex', Header/Number))]">
                <xsl:sort select="key('DocumentByNumberIndex', Header/Number)/Header" data-type="number"
                          order="ascending"/>
                <Document>
                    <Header>
                        <Number>
                            <xsl:value-of select="key('DocumentByNumberIndex', Header/Number)/Header/Number"/>
                        </Number>
                    </Header>
                    <Items>
                        <xsl:copy-of select="key('DocumentByNumberIndex', Header/Number)/Items/Item"/>
                    </Items>
                </Document>
            </xsl:for-each>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Выходной XML

<?xml version='1.0' encoding='windows-1251'?>
<Documents>
  <Document>
    <Header>
      <Number>770</Number>
    </Header>
    <Items>
      <Item>
        <Code>100</Code>
      </Item>
    </Items>
  </Document>
  <Document>
    <Header>
      <Number>999</Number>
    </Header>
    <Items>
      <Item>
        <Code>111</Code>
      </Item>
      <Item>
        <Code>222</Code>
      </Item>
      <Item>
        <Code>333</Code>
      </Item>
    </Items>
  </Document>
</Documents>

VB Script

xslt.vbs file

Option Explicit

Const strInputFile = "e:\Temp\Input.xml"
Const strTemplateFile = "e:\Temp\Process.xslt"
Const strOutputFile = "e:\Temp\Output.xml"

Dim objXMLDoc : Set objXMLDoc = WScript.CreateObject("Msxml2.DOMDocument")
objXMLDoc.async = False
objXMLDoc.load(strInputFile)

Dim objXSLDoc : Set objXSLDoc = WScript.CreateObject("Msxml2.DOMDocument")
objXSLDoc.async = False
objXSLDoc.load(strTemplateFile)

Dim objNewXMLDoc : Set objNewXMLDoc = WScript.CreateObject("Msxml2.DOMDocument")

objXMLDoc.transformNodeToObject objXSLDoc, objNewXMLDoc 
objNewXMLDoc.save strOutputFile

XSLT Launcher.cmd

Для запуска в командной строке.

wscript xslt.vbs