XSLT 1.0 и атрибуты токенизации - PullRequest
0 голосов
/ 15 декабря 2011

[править] сообщение обновлено с исправленным XML и желаемым выводом, как описано в ответе и комментариях Винсента Биранне.

Я пытаюсь собрать некоторый код для преобразования данных 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>

Ответы [ 3 ]

0 голосов
/ 15 декабря 2011

Вы были в значительной степени там, только заключили в скобки неправильную вещь, вызывающую ошибку!

<?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>
0 голосов
/ 15 декабря 2011

Я бы сделал это так:

<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>
0 голосов
/ 15 декабря 2011

Немного сложно получить именно ваш вывод с помощью 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 находится междускобка, потому что у нее один или несколько дочерних элементов.

...