Я не уверен, я полностью понимаю ваше требование, но я написал код, который первым пытается заполнить node
элементов с value
с пропавшими языками, а затем в группу на заполненных элементах:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf">
<xsl:param name="sep" as="xs:string" select="'|'"/>
<xsl:output indent="yes"/>
<xsl:variable name="main-doc" select="/"/>
<xsl:variable name="languages" as="xs:string*">
<xsl:perform-sort select="distinct-values(root/node/value/@xml:lang)">
<xsl:sort select="."/>
</xsl:perform-sort>
</xsl:variable>
<xsl:key name="k1" match="node/value" use="concat(@xml:lang, $sep, .)"/>
<xsl:template match="root">
<values>
<xsl:variable name="filled" as="element(node)*">
<xsl:apply-templates select="node" mode="fill"/>
</xsl:variable>
<xsl:for-each-group select="$filled" group-by="string-join(value, $sep)">
<group>
<xsl:copy-of select="value"/>
</group>
</xsl:for-each-group>
</values>
</xsl:template>
<xsl:template match="node" mode="fill">
<xsl:copy>
<xsl:variable name="this" as="element(node)" select="."/>
<xsl:for-each select="$languages">
<value xml:lang="{.}">
<xsl:value-of
select="if ($this/value[lang(current())])
then $this/value[lang(current())]
else (key('k1',
concat($this/value[1]/@xml:lang, $sep, $this/value[1]),
$main-doc)/../value[lang(current())])[1]"/>
</value>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Как вы можете видеть, мне нужен был какой-то заказ, чтобы заполнить элементы, поэтому я отсортировал их по отдельному @xml:lang
, я не уверен, что вы этого хотите. При таком подходе выход для входа вы публикуемый с Saxon 9.5
<values>
<group>
<value xml:lang="de">Some German Content</value>
<value xml:lang="en">Some English Content</value>
<value xml:lang="fr">Some French Content</value>
</group>
<group>
<value xml:lang="de">Some Other German Content</value>
<value xml:lang="en">Some Other English Content</value>
<value xml:lang="fr">Some Other French Content</value>
</group>
</values>
Я также не уверен, какая стратегия является намеченной один для заполнения элементов (см также комментарий я отправил). В конце концов я решил указать элементы node/value
на конкатенацию @xml:lang
и их содержимое, а затем при заполнении элементов, где отсутствует язык, я просто сопоставляю первый value
ребенок node
. Так что в основном это означает, что если у какого-то node
есть первый value xml:lang="foo"
с содержанием bar
, то матч просто на этом языке foo
и содержание bar
, и мы скопируем содержимое value
на недостающий язык.
Если вы не хотите, сортировкой и вы можете жить с порядком исходной последовательности атрибутов, то вы можете опустить сортировку, то таблица стилей, то есть
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf">
<xsl:param name="sep" as="xs:string" select="'|'"/>
<xsl:output indent="yes"/>
<xsl:variable name="main-doc" select="/"/>
<xsl:variable name="languages" as="xs:string*" select="distinct-values(root/node/value/@xml:lang)"/>
<xsl:key name="k1" match="node/value" use="concat(@xml:lang, $sep, .)"/>
<xsl:template match="root">
<values>
<xsl:variable name="filled" as="element(node)*">
<xsl:apply-templates select="node" mode="fill"/>
</xsl:variable>
<xsl:for-each-group select="$filled" group-by="string-join(value, $sep)">
<group>
<xsl:copy-of select="value"/>
</group>
</xsl:for-each-group>
</values>
</xsl:template>
<xsl:template match="node" mode="fill">
<xsl:copy>
<xsl:variable name="this" as="element(node)" select="."/>
<xsl:for-each select="$languages">
<value xml:lang="{.}">
<xsl:value-of
select="if ($this/value[lang(current())])
then $this/value[lang(current())]
else (key('k1',
concat($this/value[1]/@xml:lang, $sep, $this/value[1]),
$main-doc)/../value[lang(current())])[1]"/>
</value>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Таким образом, выход, как вы спросил:
<values>
<group>
<value xml:lang="en">Some English Content</value>
<value xml:lang="fr">Some French Content</value>
<value xml:lang="de">Some German Content</value>
</group>
<group>
<value xml:lang="en">Some Other English Content</value>
<value xml:lang="fr">Some Other French Content</value>
<value xml:lang="de">Some Other German Content</value>
</group>
</values>
Что происходит, если существует такой элемент, как '<значение XML: LANG = "FR"> Некоторые другие французские содержание<значение XML: LANG = "де"> Некоторые немецкий содержание ' ? –