XSLT1.0和标记化属性
[编辑]帖子更新了修订后的XML和预期输出,详见Vincent Biragnet的回答和评论 我正在尝试编写一些代码,将XML数据转换为基于文本的元文件。我没有运气让它吐出期望的输出,目前有点卡住了,所以任何帮助都将不胜感激 XSLT1.0并没有使标记化变得容易,这就是我遇到的问题:我希望将@syn作为CSV字符串处理,并在需要时将其拆分 我正在处理以下XML数据(请注意,除节点外,此XML文件中的所有节点都可以有任何名称。) 我当前的XSL:XSLT1.0和标记化属性,xslt,xslt-1.0,tokenize,Xslt,Xslt 1.0,Tokenize,[编辑]帖子更新了修订后的XML和预期输出,详见Vincent Biragnet的回答和评论 我正在尝试编写一些代码,将XML数据转换为基于文本的元文件。我没有运气让它吐出期望的输出,目前有点卡住了,所以任何帮助都将不胜感激 XSLT1.0并没有使标记化变得容易,这就是我遇到的问题:我希望将@syn作为CSV字符串处理,并在需要时将其拆分 我正在处理以下XML数据(请注意,除节点外,此XML文件中的所有节点都可以有任何名称。) 我当前的XSL: <?xml version="1.0"?&g
<?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精确获取输出有点棘手,但您可以使用您尝试过的mecanism。下面是一个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>
请注意您的输出的差异:
表
元素位于括号之间,因为它有一个或多个子元素。您几乎就在那里,只是在错误的东西周围放了括号,导致了错误
<?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>
就像你在这里所做的那样。它很好地给出了结果。除了我添加一些这样的节点外:
如果您运行它,您会注意到Test1节点没有在正确的行上启动。我现在正在研究这个问题。Daktari,考虑编辑你的问题,向我们展示额外的输入文档,假设它由评论不显示的几行组成。@达克塔里:我更新了XSLT来考虑你的评论。正如马丁所指出的:也许你应该在你的问题中添加这个新的XML输入。@Vincent Biragnet非常感谢你——这正是我想要的结果。是的,XSLT1.0要复杂得多。我已经更新了问题。是的,我在发布后不久就意识到了这一点。然后注意到还有一些问题。谢天谢地,现在一切都解决了。谢谢马丁。你也采取了一种有趣的方法。Vincent Biragnet的代码为我做了这项工作,但我正在仔细查看您的代码,以便从中学习。谢谢你抽出时间。
[Subject]
[People]
Jane_Doe
{janie}
{jd}
John_Doe
[Object]
[Table]
Leg
Chair
{seat}
<?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>