XSLT 1.0和标记属性



[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>&#10;</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>&#10;</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>&#10;</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="'&#10;'"/>
  <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>

相关内容

  • 没有找到相关文章

最新更新