Этот пример, на который вы ссылаетесь, слишком длинный, чтобы я мог судить об этом, но по крайней мере некоторые шаблоны написаны в стиле, который кажется слишком многословным, даже если вы не хотите использовать потоковую передачу, например
<xsl:template name="cdf:LatLng" match="element(*, cdf:LatLng)">
<xsl:param name="set_type" select="false()"/>
<xsl:where-populated>
<string key="Label">
<xsl:value-of select="@Label"/>
</string>
</xsl:where-populated>
<xsl:where-populated>
<number key="Latitude">
<xsl:value-of select="cdf:Latitude"/>
</number>
</xsl:where-populated>
<xsl:where-populated>
<number key="Longitude">
<xsl:value-of select="cdf:Longitude"/>
</number>
</xsl:where-populated>
<xsl:where-populated>
<string key="Source">
<xsl:value-of select="cdf:Source"/>
</string>
</xsl:where-populated>
<xsl:if test="not($set_type)">
<string key="@type">ElectionResults.LatLng</string>
</xsl:if>
</xsl:template>
кажется выполнимым как
<xsl:template match="LatLng">
<xsl:param name="set_type" select="false()"/>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates/>
<xsl:if test="not($set_type)">
<string key="@type">ElectionResults.LatLng</string>
</xsl:if>
</xsl:template>
, а затем для дочерних элементов и атрибутов, которые вы знаете, что это простые типы, вы просто использовали бы подход, предложенный в моем комментарии, например
<xsl:template match="element(*, xs:string)">
<string key="{local-name()}">{.}</string>
</xsl:template>
<xsl:template match="element(*, xs:double) | element(*, xs:decimal)">
<number key="{local-name()}">{.}</number>
</xsl:template>
Конечно, это в основном предполагает, что дочерние элементы должны обрабатываться в том порядке, в котором они присутствуют, и вы хотите, чтобы все они обрабатывались, но последнее ограничение можно ослабить даже при потоковой передаче, если вы используете, например, <xsl:apply-templates select="*[self::foo or self::bar]"/>
.
По крайней мере, если вы просто хотите отобразить ваши известные типы схем на JSON и прописать множество различных шаблонов для различных элементов, я думаю, что использование apply-templates
вместо указания различных дочерних выборов может помочь сделать код растекаемый. Для типов, где у вас есть возможные minOccurs = 0 и maxOccurs = unbounded, я думаю, что вы можете жить с
<xsl:for-each-group select="*" group-by="node-name()">
<xsl:variable name="sibling-group" select="copy-of(current-group())"/>
<xsl:choose>
<xsl:when test="tail($sibling-group)">
<array key="{local-name()}">
<xsl:apply-templates select="$sibling-group"/>
</array>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$sibling-group"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
вместо apply-templates
, что, конечно, "материализует" соседнюю группу элементов одного уровня. с тем же именем, но, как вы, кажется, уже подробно описали явное создание массивов в специализированных шаблонах, где вам это нужно, вы можете просто переписать эти выделенные шаблоны и не рисковать использовать этот подход вообще для любого элемента.
Если вы хотите сохранить подробный стиль с явным выбором различных дочерних элементов в одном и том же шаблоне, вы можете попробовать, насколько хорошо Saxon справится с использованием xsl:fork
, например,
<xsl:template name="cdf:LatLng" match="element(*, cdf:LatLng)">
<xsl:param name="set_type" select="false()"/>
<xsl:fork>
<xsl:sequence>
<xsl:where-populated>
<string key="Label">
<xsl:value-of select="@Label"/>
</string>
</xsl:where-populated>
</xsl:sequence>
<xsl:sequence>
<xsl:where-populated>
<number key="Latitude">
<xsl:value-of select="cdf:Latitude"/>
</number>
</xsl:where-populated>
</xsl:sequence>
<xsl:sequence>
<xsl:where-populated>
<number key="Longitude">
<xsl:value-of select="cdf:Longitude"/>
</number>
</xsl:where-populated>
</xsl:sequence>
<xsl:sequence>
<xsl:where-populated>
<string key="Source">
<xsl:value-of select="cdf:Source"/>
</string>
</xsl:where-populated>
</xsl:sequence>
</xsl:fork>
<xsl:if test="not($set_type)">
<string key="@type">ElectionResults.LatLng</string>
</xsl:if>
</xsl:template>
Использование call-template
, которое у вас также есть, будет невозможно при потоковой передаче вообще. Кажется, он также используется в этой таблице стилей для обработки XML элементов в другом порядке, нежели порядок ввода, он, похоже, выводит любые подэлементы, объявленные в абстрактных типах, после тех, которые объявлены в расширенных типах. Это, конечно, не очень хорошо работает с потоковым подходом только перенаправления, узел за узлом обработки. Так что, думаю, вам нужно решить, не можете ли вы сначала вывести базовые подэлементы в JSON.