[edit]发布更新后的修订版XML和所需的输出,详见Vincent Biragnet的回答和评论。
我正在尝试将一些代码放在一起,将XML数据转换为基于文本的元文件。我没有运气让它吐出所需的输出而且目前有点卡住了,所以任何帮助都会受到赞赏。
XSLT 1.0不会使标记化变得容易,而且这就是我陷入困境的地方:我想将@syn视为CSV字符串并在需要时将其拆分。
我正在使用以下XML数据(请注意,此XML文件中除< Meta>节点外的所有节点都可以有任何名称。)
<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>
答案 0 :(得分:0)
使用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
元素位于括号之间,因为它有一个或多个子元素。
答案 1 :(得分:0)
你几乎就在那里,只是错误的东西括号导致错误!
<?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>
答案 2 :(得分:0)
我会这样做:
<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>