这是一个简单的 XSLT 1.0 解决方案,它不包含“其他:”yaml 元素...
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*" />
<xsl:template match="*">
<xsl:call-template name="indent">
<xsl:with-param name="spaces" select="count(ancestor::*)"/>
</xsl:call-template>
<xsl:value-of select="concat( local-name(), ': ', text(), '
')"/>
<xsl:apply-templates select="*" />
</xsl:template>
<xsl:template match="ofert">
<xsl:variable name="indent" select="count(ancestor::*)" />
<xsl:call-template name="indent">
<xsl:with-param name="spaces" select="$indent"/>
</xsl:call-template>
<xsl:value-of select="concat( local-name(), ': ', text(), '
')"/>
<xsl:apply-templates select="id" />
<xsl:apply-templates select="name" />
<xsl:call-template name="indent">
<xsl:with-param name="spaces" select="$indent + 1"/>
</xsl:call-template>
<xsl:value-of select="concat(
'address: {street: ', street/text(),
', postcode: ', postcode,' }
')"/>
<xsl:call-template name="indent">
<xsl:with-param name="spaces" select="$indent + 1"/>
</xsl:call-template>
<xsl:value-of select="concat(
'work: {job: ', job,
', position: ', position, ' }
')"/>
</xsl:template>
<xsl:template name="indent">
<xsl:param name="spaces" />
<xsl:if test="$spaces > 0">
<xsl:value-of select="' '"/>
<xsl:call-template name="indent">
<xsl:with-param name="spaces" select="$spaces - 1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
XSLT 2.0 解决方案会简单得多。如果您不受 XSLT 1.0 的限制,请告诉我们。
如果有时间,我将更新解决方案以包含“其他:”元素。基本上,该技术将简单地定义一个命名模板来生成关联数组,如地址:、工作:和其他:,其中输入参数包括缩进级别、标签(“地址”等)和关联数组成员列表节点。我希望你能明白。
更新
这是 XSLT 2.0 版本,其中包括“其他”yaml 元素...
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:zzart="http://stackoverflow.com/questions/11192960">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="indent-unit" select = "' '" />
<xsl:function name="zzart:indent" as="xs:string">
<xsl:param name="level" as="xs:integer"/>
<xsl:value-of select="fn:string-join( for $in in 1 to $level return $indent-unit, '')" />
</xsl:function>
<xsl:template match="@*" />
<xsl:template match="*">
<xsl:value-of select="concat( zzart:indent( count(ancestor::*)), local-name(), ': ', text(), '
')"/>
<xsl:apply-templates select="*" />
</xsl:template>
<xsl:template match="ofert">
<xsl:variable name="level" select="count(ancestor::*)" />
<xsl:variable name="indent" select="zzart:indent( $level)" />
<xsl:value-of select="concat( $indent, local-name(), ': ', text(), '
')"/>
<xsl:apply-templates select="id" />
<xsl:apply-templates select="name" />
<xsl:call-template name="associative-array">
<xsl:with-param name="level" select="$level + 1" />
<xsl:with-param name="array-name" select="'address'" />
<xsl:with-param name="array-members" select="(street, postcode)" />
</xsl:call-template>
<xsl:call-template name="associative-array">
<xsl:with-param name="level" select="$level + 1" />
<xsl:with-param name="array-name" select="'work'" />
<xsl:with-param name="array-members" select="(job, position)" />
</xsl:call-template>
<xsl:call-template name="associative-array">
<xsl:with-param name="level" select="$level + 1" />
<xsl:with-param name="array-name" select="'other'" />
<xsl:with-param name="array-members" select="*[not(self::id)][not(self::name)]
[not(self::street)][not(self::postcode)]
[not(self::job)][not(self::position)]" />
</xsl:call-template>
</xsl:template>
<xsl:template name="associative-array">
<xsl:param name="level" as="xs:integer" />
<xsl:param name="array-name" as="xs:string" />
<xsl:param name="array-members"/>
<xsl:value-of select="concat( zzart:indent( $level), $array-name, ': {')" />
<xsl:for-each select="$array-members">
<xsl:value-of select="concat( local-name(), ': ', text(), if (position() != last()) then ', ' else ' }
')" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>