Используйте XSLT для добавления ключа ко всем дочерним узлам в XML для передачи MS Access

#xml #ms-access #xslt

Вопрос:

Я пытаюсь использовать XSLT для добавления ключа ко всем дочерним узлам, чтобы таблицы, созданные во время импорта XML в MS Access, имели соответствующий идентификатор во всех созданных таблицах. Я использовал несколько примеров, которые я нашел, чтобы собрать некоторые XSLT вместе, но я принципиально не понимаю, как это работает в той степени, в которой я могу устранить неполадки. Я могу получить Id заполнитель в Add узле, но значение пустое. Есть ли способ программно добавить Id ключ ко всем дочерним узлам без кодирования каждого из них по отдельности? Если нет, то как мне отредактировать XSLT, чтобы убедиться Id , что поле проходит?

Чтобы усложнить ситуацию, Add элемент всегда находится под ContactDetails , но ContactDetails варьируется с точки зрения узлов относительно Id элемента. Например, глубина может составлять 4-7 узлов.

Пример XML:

 <Response>


<Alices>
    <Alice>
        <Id>12345</Id>
        <Bobbers>
            <Name>John Doe</Name>
            <Bobs>
                <Bob>
                    <Organization>
                        <Name>John Doe</Name>
                        <ABB>987654</ABB>
                        <ContactDetails>
                            <Adds>
                                <Add>
                                    <Type>Postal</Type>
                                    <Line1>PO BOX 12345</Line1>
                                    <Suburb>Doeville</Suburb>
                                    <State>ENE</State>
                                    <PostCode>1111</PostCode>
                                    <Country>GB</Country>
                                    <Preferred>false</Preferred>
                                </Add>
                                <Add>
                                    <Type>Street</Type>
                                    <Line1>123 Anywhere</Line1>
                                    <Suburb>Doeville</Suburb>
                                    <State>ENE</State>
                                    <PostCode>1111</PostCode>
                                    <Country>GB</Country>
                                    <Preferred>true</Preferred>
                                </Add>
                            </Adds>
                            <PNs>
                                <PN>
                                    <Type>Mobile</Type>
                                    <Number>11111111</Number>
                                    <Preferred>true</Preferred>
                                </PN>
                            </PNS>
                            <EMs>
                                <EM>
                                    <Type>Personal</Type>
                                    <Add>j.doe@anywhere.com</Add>
                                    <Preferred>false</Preferred>
                                </EM>
                            </EMs>
                            <PreferredContactMethod>Email</PreferredContactMethod>
                        </ContactDetails>
                        <Contacts>
                            <Contact>
                                <LastName>Doe</LastName>
                                <FirstName>John</FirstName>
                            </Contact>
                        </Contacts>
                    </Organization>
                </Bob>
            </Bobs>
        </Bobbers>
        <Jons>
            <Jon>
                <Id>012991</Id>
                <PrimaryJon>true</PrimaryJon>
                <StartDate>1900-01-01</StartDate>
            </Jon>
        </Jons>
    </Alice>
</Alices>

</Response>
 

И XSLT:

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

    <xsl:template match="/">
        <dataroot>
            <xsl:apply-templates select="@*|node()"/>
        </dataroot>
    </xsl:template>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="Adds">
        <xsl:apply-templates select="@*|node()"/>
    </xsl:template>

    <xsl:template match="Add">
        <Add>
            <Id><xsl:value-of select="../../Id"/></Id>
            <xsl:apply-templates select="@*|node()"/>
        </Add>
    </xsl:template>

</xsl:stylesheet>
 

И вот что мне нужно:

 <Response>

<Alices>
    <Alice>
        <Id>12345</Id>
        <Bobbers>
            <Name>John Doe</Name>
            <Bobs>
                <Bob>
                    <Organization>
                        <Id>12345</Id>
                        <Name>John Doe</Name>
                        <ABB>987654</ABB>
                        <ContactDetails>
                            <Adds>
                                <Add>
                                    <Id>12345</Id>
                                    <Type>Postal</Type>
                                    <Line1>PO BOX 12345</Line1>
                                    <Suburb>Doeville</Suburb>
                                    <State>ENE</State>
                                    <PostCode>1111</PostCode>
                                    <Country>GB</Country>
                                    <Preferred>false</Preferred>
                                </Add>
                                <Add>
                                    <Id>12345</Id>                              
                                    <Type>Street</Type>
                                    <Line1>123 Anywhere</Line1>
                                    <Suburb>Doeville</Suburb>
                                    <State>ENE</State>
                                    <PostCode>1111</PostCode>
                                    <Country>GB</Country>
                                    <Preferred>true</Preferred>
                                </Add>
                            </Adds>
                            <PNs>
                                <PN>
                                    <Id>12345</Id>                              
                                    <Type>Mobile</Type>
                                    <Number>11111111</Number>
                                    <Preferred>true</Preferred>
                                </PN>
                            </PNS>
                            <EMs>
                                <EM>
                                    <Id>12345</Id>                              
                                    <Type>Personal</Type>
                                    <Add>j.doe@anywhere.com</Add>
                                    <Preferred>false</Preferred>
                                </EM>
                            </EMs>
                            <PreferredContactMethod>Email</PreferredContactMethod>
                        </ContactDetails>
                        <Contacts>
                            <Contact>
                                <Id>12345</Id>                          
                                <LastName>Doe</LastName>
                                <FirstName>John</FirstName>
                            </Contact>
                        </Contacts>
                    </Organization>
                </Bob>
            </Bobs>
        </Bobbers>
        <Jons>
            <Jon>
                <Id>012991</Id>
                <PrimaryJon>true</PrimaryJon>
                <StartDate>1900-01-01</StartDate>
            </Jon>
        </Jons>
    </Alice>
</Alices>

</Response>
 

Комментарии:

1. .. выбирает родительский элемент, ../.. прародителя, таким образом ../../Id выбирает Id дочерний элемент прародителя. Для Add элемента бабушка и дедушка-это ContactDetails элемент, у которого нет никакого Id ребенка. Непонятно, почему вы ожидаете, что это даст что-то, кроме пустого значения.

2. Пожалуйста, отредактируйте свой вопрос и добавьте ожидаемый результат.

3. @michael.hor257k добавил: спасибо.

4. @MartinHonnen Это полезно, спасибо.

5. Существует ли логика, которая определяет, какие элементы должны получить Id элемент? Почему Organization , но нет Bobbers ?

Ответ №1:

Попробуйте в соответствии с

 <xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0">

  <xsl:output method="xml" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="*[*[not(*)] and ancestor::*[Id]]">
    <xsl:copy>
      <xsl:apply-templates select="ancestor::*[Id]/Id | *"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
 

Комментарии:

1. Спасибо, Мартин. К сожалению, я не могу получить никакой информации, используя это. Для записи образца я могу получить информацию с помощью <Id><xsl:value-of select="../../../../../../../Id"/></Id> , но поскольку Id элемент не всегда находится в одном и том же месте, для некоторых записей Id он пуст.

2. Непонятно, почему это предложение не работает, оно работает для меня в xsltfiddle. liberty-development.net/nbspVab . Я полагаю, что вы, возможно, вернулись к своей предыдущей проблеме с пространством имен, но вам это невозможно сказать.

3. Я не думаю, что это проблема с пространством имен, так как я удалил ссылку на него для тестирования. Я взял некоторые производственные данные и, используя ваш XSLT, могу копировать Id элемент везде, где мне нужно, так что спасибо за это. Я думаю, что виновником может быть MS Access… При использовании одного и того же XML и XSLT во время преобразования Id в Add блоке не отображается ни один элемент.

4. В xsltfiddle. liberty-development.net/nbspVab/1 Я использовал MSXML 6 вместо XslCompiledTransform. Я бы сказал, что MS Access использует версию MSXML для запуска XSLT, не могу сказать, какую именно, но, похоже, она работает с MSXML 6, которая доступна во всех поддерживаемых версиях ОС Windows. Я не знаю, можете ли вы или как вы можете получить доступ к использованию MSXML 6, но я действительно не вижу причин, по которым MSXML 3 или 5 потерпит неудачу.

5. Обновление: На самом деле это работает для всех узлов… Я обнаружил, что был еще один узел с другим именем, который предшествовал Bobbers узлу, у которого также был Add узел. По какой-то причине, когда я создал пустой шаблон для этого другого узла <xsl:template match="ExtraNode"></xsl:template> Id , элемент появился в Add блоке.