[edit] post更新了修订后的XML和期望的输出,详细信息请参见Vincent Biragnet的回答和评论。
我试图把一些代码把XML数据转换成一个基于文本的元文件。我没有运气让它吐出想要的输出,我目前有点卡住了,所以任何帮助都会很感激。
XSLT 1.0没有使标记化变得容易,这就是我卡住的地方:我想将@syn视为CSV字符串,并在需要时将其分解。
我正在处理以下XML数据(请注意所有节点,除了
节点,在此XML文件中可以有任何名称)<Meta>
<Subject>
<People>
<Jane_Doe syn="janie, jd" />
<John_Doe/>
</People>
<Object>
<Table>
<Leg/>
</Table>
<Chair syn="seat" />
</Object>
</Subject>
<Test1>
<Test2 syn="testy"/>
<Test3>
<Test4/>
</Test3>
</Test1>
</Meta>
这个XML需要转换,所以输出看起来是这样的:
[Subject]
[People]
Jane_Doe
{janie}
{jd}
John_Doe
[Object]
[Table]
Leg
Chair
{seat}
[Test1]
Test2
{testy}
[Test3]
Test4
我当前的XSL:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" indent="yes"/>
<xsl:template match="/Meta"><xsl:apply-templates/></xsl:template>
<xsl:template match="child::*"><xsl:call-template name="master"/><xsl:apply-templates/></xsl:template>
<xsl:template name="master">
<xsl:choose>
<xsl:when test="count(child::*) = 0">
<xsl:value-of select="local-name()"/>
<xsl:apply-templates select="@syn"/>
</xsl:when>
<xsl:otherwise>
[<xsl:value-of select="local-name()"/>]
<xsl:apply-templates select="@syn"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="tokenize" match="@syn">
<xsl:param name="text" select="."/>
<xsl:param name="separator" select="','"/>
<xsl:value-of select="$text"/>
<xsl:choose>
<xsl:when test="not(contains($text, $separator))">
{<xsl:value-of select="normalize-space($text)"/>}
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="normalize-space(substring-before($text, $separator))"/>
<xsl:call-template name="tokenize">
{<xsl:with-param name="text" select="substring-after($text, $separator)"/>}
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
使用XSLT 1.0获得准确的输出有点棘手,但是您可以使用您尝试过的机制。下面是一个XSLT 1.0,它的输出带有缩进:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="Meta">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="*">
<xsl:param name="depth" select="0"/>
<xsl:choose>
<xsl:when test="$depth > 0">
<xsl:text> </xsl:text>
<xsl:call-template name="addSpace">
<xsl:with-param name="nb" select="$depth"></xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="position() > 1">
<xsl:text> </xsl:text>
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="count(*) > 0">
<xsl:text>[</xsl:text>
<xsl:value-of select="local-name()"/>
<xsl:text>]</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="local-name()"/>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="@syn|*">
<xsl:with-param name="depth" select="$depth + 1"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template name="tokenize" match="@syn">
<xsl:param name="text" select="."/>
<xsl:param name="depth" select="1"/>
<xsl:param name="separator" select="','"/>
<xsl:text> </xsl:text>
<xsl:call-template name="addSpace">
<xsl:with-param name="nb" select="$depth"></xsl:with-param>
</xsl:call-template>
<xsl:choose>
<xsl:when test="not(contains($text, $separator))">
<xsl:text>{</xsl:text>
<xsl:value-of select="normalize-space($text)"/>
<xsl:text>}</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>{</xsl:text>
<xsl:value-of select="normalize-space(substring-before($text, $separator))"/>
<xsl:text>}</xsl:text>
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="substring-after($text, $separator)"/>
<xsl:with-param name="separator" select="$separator"/>
<xsl:with-param name="depth" select="$depth"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="addSpace">
<xsl:param name="nb"/>
<xsl:text> </xsl:text>
<xsl:if test="$nb >1 ">
<xsl:call-template name="addSpace">
<xsl:with-param name="nb" select="$nb - 1"></xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
输入的结果是:
[Subject]
[People]
Jane_Doe
{janie}
{jd}
John_Doe
[Object]
[Table]
Leg
Chair
{seat}
注意与输出的区别:table
元素在括号之间,因为它有一个或多个子元素。
你差不多在那里,只是用括号把错误的东西引起错误!
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" indent="yes"/>
<xsl:template match="/Meta"><xsl:apply-templates/></xsl:template>
<xsl:template match="child::*"><xsl:call-template name="master"/><xsl:apply-templates/></xsl:template>
<xsl:template name="master">
<xsl:choose>
<xsl:when test="count(child::*) = 0">
<xsl:value-of select="local-name()"/>
<xsl:apply-templates select="@syn"/>
</xsl:when>
<xsl:otherwise>
[<xsl:value-of select="local-name()"/>]
<xsl:apply-templates select="@syn"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="tokenize" match="@syn">
<xsl:param name="text" select="."/>
<xsl:param name="separator" select="','"/>
<xsl:choose>
<xsl:when test="not(contains($text, $separator))">
{<xsl:value-of select="normalize-space($text)"/>}
</xsl:when>
<xsl:otherwise>
{<xsl:value-of select="normalize-space(substring-before($text, $separator))"/>}
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="substring-after($text, $separator)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
我会这样做:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="text"/>
<xsl:param name="lf" select="' '"/>
<xsl:param name="start-indent" select="' '"/>
<xsl:param name="br1" select="'['"/>
<xsl:param name="br2" select="']'"/>
<xsl:param name="br3" select="'{'"/>
<xsl:param name="br4" select="'}'"/>
<xsl:param name="sep" select="','"/>
<xsl:template match="/Meta" priority="10">
<xsl:apply-templates select="*">
<xsl:with-param name="indent" select="''"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*[not(*)]">
<xsl:param name="indent"/>
<xsl:value-of select="concat($indent, local-name(), $lf)"/>
<xsl:apply-templates select="@syn">
<xsl:with-param name="indent" select="concat($indent, $start-indent)"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="*[*]">
<xsl:param name="indent"/>
<xsl:value-of select="concat($indent, $br1, local-name(), $br2, $lf)"/>
<xsl:apply-templates select="*">
<xsl:with-param name="indent" select="concat($indent, $start-indent)"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="@syn">
<xsl:param name="indent"/>
<xsl:param name="text" select="."/>
<xsl:choose>
<xsl:when test="not(contains($text, $sep))">
<xsl:if test="normalize-space($text)">
<xsl:value-of select="concat($indent, $br3, normalize-space($text), $br4, $lf)"/>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat($indent, $br3, normalize-space(substring-before($text, $sep)), $br4, $lf)"/>
<xsl:apply-templates select=".">
<xsl:with-param name="indent" select="$indent"/>
<xsl:with-param name="text" select="substring-after($text, $sep)"/>
</xsl:apply-templates>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>