Мне нужно убедиться, что документ XML всегда содержит следующие узлы:
<group>
<section>0001</section>
<head>0002</head>
<body>0003</body>
</group>
Типичный XML-файл ввода выглядит следующим образом (узел группы всегда должен предшествовать категории и сводке):
<story>
<group>
<section>section-content</section>
<head>head-content</head>
<body>body-content</body>
<extra>extra-content</extra>
</group>
<category>some text</category>
<summary>some text</summary>
</story>
Но нет никакой гарантии, что элемент группы или любой из его дочерних элементов будет существовать.
Итак, учитывая XML-документ:
<story>
<category>some text</category>
<summary>some text</summary>
</story>
Вывод должен выглядеть следующим образом:
<story>
<group>
<section>0001</section>
<head>0002</head>
<body>0003</body>
</group>
<category>some text</category>
<summary>some text</summary>
</story>
XSLT не должен изменять существующее содержимое, например.
<story>
<group>
<section>existing text</section>
<extra>existing text</extra>
</group>
<category>some text</category>
<summary>some text</summary>
</story>
Должен преобразоваться в:
<story>
<group>
<section>existing text</section>
<head>0002</head>
<body>0003</body>
<extra>existing text</extra>
</group>
<category>some text</category>
<summary>some text</summary>
</story>
Используя ответ Томалака за основу, я придумал следующее:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:subst="http://tempuri.com/mysubst"
>
<xsl:strip-space elements="*"/>
<xsl:output method="xml" encoding="utf-8" indent="yes"/>
<!-- These defaults (elements and contents) can be modified at any time -->
<subst:defaults>
<subst:element name="group">
<subst:section>0001</subst:section>
<subst:head>0002</subst:head>
<subst:body>0002</subst:body>
</subst:element>
</subst:defaults>
<!-- this makes the above available as a variable -->
<xsl:variable name="defaults" select="document('')/*/subst:defaults" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="story[not(group)]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:element name="group"></xsl:element>
<xsl:apply-templates select="node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="group">
<xsl:copy>
<xsl:copy-of select="@*|*"/>
<xsl:call-template name="create-defaults" />
</xsl:copy>
</xsl:template>
<!-- Insert the defaults-->
<xsl:template name="create-defaults">
<xsl:variable name="this" select="." />
<xsl:for-each select="$defaults/subst:element[@name = name($this)]/*">
<xsl:if test="not($this/*[name() = local-name(current())])">
<xsl:apply-templates select="." />
</xsl:if>
</xsl:for-each>
</xsl:template>
<!-- Remove the namespaces -->
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates select="@*|node()"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Кажется, работает, если элемент группы уже существует, но я не могу понять, как заставить его работать, если элемент группы не существует.