#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
блоке.