XSLT: complex conversions, sentences?

I need to create an XSLT stylesheet that converts xml as follows:

<message>
 <line/> 
 <silence/> 
 <dot/><line/><line/> 
 <silence/> 
 <dot/> 
 <silence/> 
 <line/><dot/><dot/><dot/> 
</message> 

into something like this:

<complexMessage> 
 <word code="-"/> 
 <word code=".--"/> 
 <word code="."/>
 <word code="-..."/> 
</complexMessage> 

(note that each item wordcloses after the item silence)

How can i do this?

+3
source share
3 answers

This solution: a little shorter and, more importantly, more efficient thanks to the use of keys :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:key name="kPhraseByMorse" 
           match="*[not(self::silence) and not(self::message)]" 
           use="generate-id(preceding-sibling::silence[1])"/>

    <xsl:template match="/">
      <complexMessage>
        <word>
          <xsl:call-template name="makeCode"/>
        </word>

        <xsl:apply-templates select="*/silence"/>
      </complexMessage>
    </xsl:template>

    <xsl:template match="silence">
      <word>
     <xsl:call-template name="makeCode">
       <xsl:with-param name="pId" select="generate-id()"/>
     </xsl:call-template>
      </word>
    </xsl:template>

    <xsl:template name="makeCode">
      <xsl:param name="pId"/>
      <xsl:attribute name="code">
        <xsl:apply-templates select="key('kPhraseByMorse', $pId)"/>
      </xsl:attribute>
    </xsl:template>

    <xsl:template match="dot">.</xsl:template>
    <xsl:template match="line">-</xsl:template>
</xsl:stylesheet>

When this conversion is applied to the provided XML source, the correct result is obtained :

<complexMessage>
   <word code="-"/>
   <word code=".--"/>
   <word code="."/>
   <word code="-..."/>
</complexMessage>
+3
source

I believe that this provides what you are looking for:

    <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:variable name="firstSilenceID" select="generate-id(//silence[1])" />
    <xsl:template match="/">
        <complexMessage>
            <xsl:apply-templates select="/message//silence"/>
        </complexMessage>
    </xsl:template>

    <xsl:template name="message">

    </xsl:template>

    <xsl:template match="silence" >
        <!--If this is the first <silince> element, generate words for everything before it -->
        <xsl:if test="$firstSilenceID = generate-id(current())">
            <xsl:call-template name="complexMessage">
                <xsl:with-param name="word" select="preceding-sibling::*"/>
            </xsl:call-template>
        </xsl:if>
        <!--Generate words for everything after THIS <silence> element -->
        <xsl:call-template name="complexMessage">
            <xsl:with-param name="word" select="following-sibling::*[generate-id(preceding-sibling::silence[1]) = generate-id(current())]"/>
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="complexMessage">
        <xsl:param name="word"/>
            <word>
                <xsl:attribute name="code">
                    <xsl:apply-templates select="$word" />
                </xsl:attribute>
            </word>
    </xsl:template>

    <xsl:template match="dot">
        <xsl:text>.</xsl:text>
    </xsl:template>

    <xsl:template match="line">
        <xsl:text>-</xsl:text>
    </xsl:template>

</xsl:stylesheet>
+2
source

:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="/message">
      <complexMessage>
        <xsl:apply-templates select="*[1]"/>
      </complexMessage>
    </xsl:template>
  <xsl:template match="line" mode="value">-</xsl:template>
  <xsl:template match="dot" mode="value">.</xsl:template>
  <xsl:template match="silence" mode="value"/>

  <xsl:template match="silence" name="write">
    <xsl:param name="prev" select="''"/>
    <word code="{$prev}"/>
    <xsl:apply-templates select="following-sibling::*[1]"/>
  </xsl:template>
  <xsl:template match="line | dot">
    <xsl:param name="prev" select="''"/>
    <xsl:variable name="value"><xsl:apply-templates select="." mode="value"/></xsl:variable>
    <xsl:choose>
      <xsl:when test="following-sibling::*">
        <xsl:apply-templates select="following-sibling::*[1]">
          <xsl:with-param name="prev" select="concat($prev,$value)"/>
        </xsl:apply-templates>
      </xsl:when>
      <xsl:otherwise>
        <xsl:call-template name="write">
          <xsl:with-param name="prev" select="concat($prev,$value)"/>
        </xsl:call-template>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

- -, <xsl:apply-templates select="*[1] | silence"/>, EOF ( , ). , , ...

+1
source

Source: https://habr.com/ru/post/1715811/


All Articles