Я преобразовываю файлы XML, которые не содержат каждый элемент схемы. Какую технику я должен использовать в своем XSLT-файле, чтобы полученный XML-файл содержал все элементы, указанные в схеме?Создание XSLT 1.0 Создание XML с учетом схемы
Я знаю, что XSLT 2.0 может решить эту проблему легко, но я застрял с XSLT 1.0.
Пол
Вот пример того, что я пытаюсь сделать:
Schema.xml
<SAN>
<STACKMEMBERS>
<STACKMEMBER>
<A/>
<B/>
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<C/>
<D/>
<E/>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
</STACKMEMBERS>
</SAN>
DataFile.xml
<SAN>
<STACKMEMBERS>
<STACKMEMBER>
<A>1111</A>
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<D>3333</D>
<E>4444</E>
</ETHERNETSWITCH>
<ETHERNETSWITCH>
<D>5555</D>
<E>6666</E>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
<STACKMEMBER>
<A>2222</A>
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<D>7777</D>
<E>8888</E>
</ETHERNETSWITCH>
<ETHERNETSWITCH>
<D>9999</D>
<E>1010</E>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
</STACKMEMBERS>
</SAN>
Желаемая Выход:
<SAN>
<STACKMEMBERS>
<STACKMEMBER>
<A>1111</A>
<B />
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<C />
<D>3333</D>
<E>4444</E>
</ETHERNETSWITCH>
<ETHERNETSWITCH>
<C />
<D>5555</D>
<E>6666</E>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
<STACKMEMBER>
<A>2222</A>
<B />
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<C />
<D>7777</D>
<E>8888</E>
</ETHERNETSWITCH>
<ETHERNETSWITCH>
<C />
<D>9999</D>
<E>1010</E>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
</STACKMEMBERS>
</SAN>
Мой текущий файл XSLT является ...
<?xml version="1.0" encoding="windows-1252"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="schemaFile" select="document('Schema.xml')"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*">
<SAN>
<STACKMEMBERS>
<xsl:for-each select="/SAN/STACKMEMBERS/STACKMEMBER">
<xsl:copy-of select="."/>
<xsl:copy-of select="$schemaFile/SAN/STACKMEMBERS/STACKMEMBER"/>
</xsl:for-each>
</STACKMEMBERS>
</SAN>
</xsl:template>
</xsl:stylesheet>
... и это дает мне неправильные результаты:
<SAN>
<STACKMEMBERS>
<STACKMEMBER>
<A>1111</A>
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<D>3333</D>
<E>4444</E>
</ETHERNETSWITCH>
<ETHERNETSWITCH>
<D>5555</D>
<E>6666</E>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
<STACKMEMBER>
<A />
<B />
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<C />
<D />
<E />
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
<STACKMEMBER>
<A>2222</A>
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<D>7777</D>
<E>8888</E>
</ETHERNETSWITCH>
<ETHERNETSWITCH>
<D>9999</D>
<E>1010</E>
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
<STACKMEMBER>
<A />
<B />
<ETHERNETSWITCHES>
<ETHERNETSWITCH>
<C />
<D />
<E />
</ETHERNETSWITCH>
</ETHERNETSWITCHES>
</STACKMEMBER>
</STACKMEMBERS>
</SAN>
Примечание что элементы B и C определены в схеме, но не представлены в файле данных. Желаемый результат должен добавлять элементы, содержащиеся только в схеме, в файл данных.
Было бы неплохо иметь несколько критериев для выбора (например, select = (один, два)). Я чувствую, что я рядом, но нуждаюсь в небольшом нажатии, чтобы получить желаемый результат.
Пол
Вот полный XSLT-файл, переработанный с шаблоном Майкла Кея, что это не совсем рабочий:
<?xml version="1.0" encoding="windows-1252"?>
<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="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="Instance" select="/"/>
<xsl:variable name="Schema" select="document('schema.xml')"/>
<xsl:template match="*">
<xsl:copy>
<xsl:variable name="E" select="."/>
<xsl:variable name="S" select="$Schema//*[name(.)=name($E)]"/>
<xsl:for-each select="$S/*">
<xsl:variable name="SC" select="."/>
<xsl:variable name="EC" select="$E/*[name(.)=name($SC)]"/>
<xsl:choose>
<xsl:when test="$EC">
<xsl:apply-templates select="$EC"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$SC"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Я написал шаблон, который должен возвращать элемент XPath. Затем я модифицировал приведенный выше шаблон, чтобы искать элементы XPath вместо имени элемента. Результатом является переполнение стека, и я не знаю, где я ошибся.
Это код XSLT, который не работает. Любая помощь приветствуется.
Пол
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2011-03-16T10:53:27">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="Data" select="/"/>
<xsl:variable name="Schema" select="document('MainDataSource.xml')"/>
<xsl:template match="*[not(*)]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template name="GetXPath">
<xsl:param name="element"/>
<xsl:if test="not(*)">
<xsl:apply-templates select="ancestor-or-self::*" mode="path"/>
</xsl:if>
</xsl:template>
<xsl:template match="*" mode="path">
<xsl:value-of select="concat('/',name())"/>
</xsl:template>
<xsl:template match="*">
<xsl:copy>
<xsl:variable name="DataElement" select="."/>
<xsl:variable name="DataElementXPath">
<xsl:call-template name="GetXPath">
<xsl:with-param name="element" select="$DataElement"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="SchemaElement" select="$Schema/*[$DataElementXPath]"/>
<xsl:for-each select="$SchemaElement/*">
<xsl:variable name="SchemaChild" select="."/>
<xsl:variable name="SchemaChildXPath">
<xsl:call-template name="GetXPath">
<xsl:with-param name="element" select="$SchemaChild"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="DataChild" select="$Data/*[$SchemaChildXPath]"/>
<xsl:choose>
<xsl:when test="$DataChild">
<xsl:apply-templates select="$DataChild"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="$SchemaChild"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
(Не в теме, я сделал двойной прием: я просто читаю Джона Ле Карре «Деликатная истина», в которой главный герой маскируется, как Пол Андерсон). –