XML в XML XSLT-преобразование. MS XML в VBScript - PullRequest
0 голосов
/ 23 января 2020

У меня есть довольно вложенный файл XML, который я хотел бы преобразовать с помощью шаблона XSL во что-то немного более простое, чтобы сделать массовую загрузку данных в SQL более эффективной. Я хотел сделать это на C ++ (кодовые блоки с g cc), но у меня возникли некоторые проблемы с возможностью загрузки документа с любой из библиотек, с которыми я сталкивался, включая MS XML. Если у кого-то есть опыт использования MS XML в Codeblocks с g cc, дайте мне знать!

У меня есть таблица стилей, которая преобразует XML в Excel VBA с DOMDocument, но я не хочу зависеть от Excel. Я подумал, что следующим лучшим вариантом будет VBScript.

Данные - это одно или два текстовых значения, которые хранятся в <DATAVALUE> узлах, потомках 100 <LOCATION> узлов. Первый дочерний элемент каждого узла <LOCATION>, называемый <LOCATIONNAME>, содержит уникальное имя для каждого узла <LOCATION> (т. Е. NAME1 - NAME100). Третий и четвертый дочерние узлы <LOCATION> узла (если есть четвертый дочерний узел) являются <DATA> узлами, каждый из которых содержит <DATAVALUE> узел. Файл может иметь более 1 миллиона <SAMPLE> узлов. Вот XML:

<?xml version="1.0" encoding="utf-8"?>
<MYImportFile xmlns="urn:ohLookHEREaNamespacedeclaration">
  <HEADERVERSION>1.10</HEADERVERSION>
  <MESSAGE>Import</MESSAGE>
  <MYBED>QUEEN</MYBED>
  <SOURCE>SPRING </SOURCE>
  <USERID>MMOUSE</USERID>
  <DATETIME>2019-11-25T12:31:00</DATETIME>
  <SAMPLE TYPE="No" APPLE="false">
    <SAMPLEID>0000565</SAMPLEID>
    <SAMPLECATEGORY>CLASS5</SAMPLECATEGORY>
    <LOCATION APPLE="false">
      <LOCATIONNAME>NAME1</LOCATIONNAME>
      <READBY>MMOUSE</READBY>
      <TIME>12:31:00</TIME>
      <DATA>
        <DATAVALUE>aaaa</DATAVALUE>
      </DATA>
      <DATA>
        <DATAVALUE>bbbb</DATAVALUE>
      </DATA>
    </LOCATION>
    '''''''''''''''''there are 100 LOCATION entries''''''''''''''''''''''''
    <LOCATION APPLE="false">
      <LOCATIONNAME>NAME100</LOCATIONNAME>
      <READBY>MMOUSE</READBY>
      <TIME>12:31:00</TIME>
      <DATA>
        <DATAVALUE>zzzz</DATAVALUE>
      </DATA>
    </LOCATION>
  </SAMPLE>
  '''''''''''''''''repeat for however many SAMPLES there are''''''''''''''''''''''
</MYImportFile>

Я хочу кое-что указать, чтобы было немного яснее, что происходит. В преобразованном документе xml я должен учитывать одну вещь, когда в <LOCATION> есть только один узел <DATA>. Это делается путем копирования первого узла <DATAVALUE> во второй узел <DATAVALUE> в новом документе. Например, <DATAVALUE>, "zzzz", которые появляются дважды в преобразованном листе, появляются только в исходных XML один раз. Вот что я хочу, чтобы преобразованный XML выглядел так:

<?xml version="1.0" encoding="UTF-8"?>
<MYImportFile>
    <SAMPLE>
        <SAMPLEID>0000565</SAMPLEID>
        <NAME1_1>aaaa</NAME1_1>
        <NAME1_2>bbbb</NAME1_2>
        <NAME2_1>cccc</NAME2_1>
        <NAME2_2>dddd</NAME2_2>
        '''''''''''''''''there are 100 LOCATION entries transformed to NAME1-NAME100''''''''''''''''''''''''
        <NAME100_1>zzzz</NAME100_1>
        <NAME100_2>zzzz</NAME100_2>
    </SAMPLE>
    '''''''''''''''''repeat for however many SAMPLES there are''''''''''''''''''''''
</MYImportFile>

Моя таблица стилей (которая работает с кодом VBA):

<?xml version="1.0" encoding="utf-8"?>

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:b="urn:ohLookHEREaNamespacedeclaration" exclude-result-prefixes="b">

<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/b:MYImportFile">

<MYImportFile>

    <xsl:for-each select="b:SAMPLE">

    <SAMPLE>

        <SAMPLEID>
        <xsl:value-of select="b:SAMPLEID"/>
        </SAMPLEID>

        <NAME1_1>
        <xsl:value-of select="b:LOCATION/b:LOCATIONNAME[text() = 'NAME1']/../b:DATA[1]/b:DATAVALUE"/>
        </NAME1_1>

        <xsl:choose> 
            <xsl:when test="b:LOCATION/b:LOCATIONNAME[text() = 'NAME1']/../b:DATA[2]/b:DATAVALUE">
                <NAME1_2>
                <xsl:value-of select="b:LOCATION/b:LOCATIONNAME[text() = 'NAME1']/../b:DATA[2]/b:DATAVALUE"/>
                </NAME1_2>
            </xsl:when>
            <xsl:otherwise>
                <NAME1_2>
                <xsl:value-of select="b:LOCATION/b:LOCATIONNAME[text() = 'NAME1']/../b:DATA[1]/b:DATAVALUE"/>
                </NAME1_2>
            </xsl:otherwise>
        </xsl:choose>


        '''''''''''''''''''there are 100 NAME entires to recieve the 100 locations

    </SAMPLE>

    </xsl:for-each>

</MYImportFile>

</xsl:template>
</xsl:stylesheet>

Мой сценарий:

Option Explicit

Const strInputFile = "C:\Path\fileName.xml"
Const strTemplateFile = "C:\Path\convFileName.xsl"
Const strOutputFile = "C:\Path\newFileName.xml"

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

objXMLDoc.SetProperty "SelectionNamespaces", "xmlns='urn:myNamespace'"

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


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

objXMLDoc.transformNodeToObject objXSLDoc, objNewXMLDoc 
objNewXMLDoc.save strOutputFile

Ошибка:

Строка: 19

Char: 1

Ошибка: таблица стилей не содержит элемент документа. Таблица стилей может быть пустой или неправильной формы XML документ.

Код: 80004005

Источник: msxml3.dll

I Я предполагаю, что либо мой сценарий не совсем правильный, либо есть пропущенная настройка, что приводит к несовпадению объектов и библиотек, потому что мой макрос VBA преобразует xml с этой таблицей стилей. У кого-нибудь есть идеи? Предложения, чтобы заставить эту вещь работать?

1 Ответ

1 голос
/ 23 января 2020

Насколько я помню loadXML берет строку с XML. Если у вас есть файл или URL для анализа, используйте метод load.

...