home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / WindowsServerTrial / server.iso / sources / install.wim / 1 / Windows / System32 / msfeeds.dll / HTML / SHAREDNORMALIZER.XSL < prev   
Extensible Markup Language  |  2008-01-19  |  50KB  |  1,165 lines

  1. <?xml version="1.0"?>
  2. <xsl:stylesheet version="1.0"
  3.     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  4.     xmlns:atom="http://www.w3.org/2005/Atom"
  5.     xmlns:cf="http://www.microsoft.com/schemas/rss/core/2005" 
  6.     xmlns:msfeednorm="urn:microsoft:feed-normalization"
  7.     exclude-result-prefixes="msfeednorm"
  8.     >
  9.  
  10. <!-- IMPORTANT: This shared XSL gets imported using our code by copying all the xsl:stylesheet's children, 
  11. so all of the above namespace declarations must be present in each other XSL where this is imported into. -->
  12.  
  13. <!-- Download URL is inserted from the normalization code -->
  14.   <xsl:param name="downloadUrl" />
  15.  
  16. <!-- 
  17. Namespaces commonly used in RSS feeds 
  18. -->
  19.  
  20. <xsl:variable name="_NSatom1" select="'http://www.w3.org/2005/Atom'" />
  21. <xsl:variable name="_NSatom03" select="'http://purl.org/atom/ns#'" />
  22. <xsl:variable name="_NSsy" select="'http://purl.org/rss/1.0/modules/syndication/'" />
  23. <xsl:variable name="_NScontent" select="'http://purl.org/rss/1.0/modules/content/'" />
  24. <xsl:variable name="_NSrdf" select="'http://www.w3.org/1999/02/22-rdf-syntax-ns#'" />
  25. <xsl:variable name="_NSrss" select="'http://purl.org/rss/1.0/'" />
  26. <xsl:variable name="_NSdc" select="'http://purl.org/dc/elements/1.1/'" />
  27. <xsl:variable name="_NSdcterms" select="'http://purl.org/dc/terms/'" />
  28. <xsl:variable name="_NSslash" select="'http://purl.org/rss/1.0/modules/slash/'" />
  29. <xsl:variable name="_NSwfw" select="'http://wellformedweb.org/CommentAPI/'" />
  30. <xsl:variable name="_NScf" select="'http://www.microsoft.com/schemas/rss/core/2005'" />
  31. <xsl:variable name="_NScfi" select="'http://www.microsoft.com/schemas/rss/core/2005/internal'" />
  32. <xsl:variable name="_NSxhtml" select="'http://www.w3.org/1999/xhtml'" />
  33.  
  34.  
  35. <!--
  36. Conversion and utility/helper templates
  37. -->
  38.  
  39. <!-- Find if current node is a first one of its kind; returns strings 'true' when first or 'false' when not -->
  40. <xsl:template name="_IsFirstChildOfItsKind">
  41.   <xsl:param name="value" />
  42.   <xsl:variable name="_nameSpace" select="namespace-uri($value)" />
  43.   <xsl:variable name="_localName" select="local-name($value)" />
  44.   <xsl:variable name="_currentId" select="generate-id($value)"/>
  45.   <xsl:variable name="_firstId" select="generate-id($value/../*[namespace-uri(.) = $_nameSpace and local-name(.) = $_localName])"/>
  46.   <xsl:choose>
  47.     <xsl:when test="$_currentId = $_firstId">
  48.       <xsl:value-of select="'true'" />
  49.     </xsl:when>
  50.     <xsl:otherwise>
  51.       <xsl:value-of select="'false'" />
  52.     </xsl:otherwise>
  53.   </xsl:choose>
  54. </xsl:template>
  55.  
  56. <!-- Convert updateFrequency and updatePeriod to ttl -->
  57.   <xsl:template name="_ConvertUpdatesToTtl">
  58.     <xsl:param name="updateFrequency" />
  59.     <xsl:param name="updatePeriod" />
  60.     <xsl:variable name="_updateFrequencyNum" select="number($updateFrequency)"/>
  61.     <xsl:variable name="_updatePeriodTmp">
  62.       <xsl:choose>
  63.         <xsl:when test="$updatePeriod = 'hourly'">60</xsl:when>
  64.         <xsl:when test="$updatePeriod = 'daily'">1440</xsl:when>
  65.         <xsl:when test="$updatePeriod = 'weekly'">10080</xsl:when>
  66.         <xsl:when test="$updatePeriod = 'monthly'">40320</xsl:when>
  67.         <xsl:when test="$updatePeriod = 'yearly'">483840</xsl:when>
  68.         <xsl:otherwise>-1</xsl:otherwise>
  69.       </xsl:choose>
  70.     </xsl:variable>
  71.     <xsl:variable name="_updatePeriodNum" select="number($_updatePeriodTmp)" />
  72.     <xsl:if test="$_updateFrequencyNum >= 0 and $_updatePeriodNum > 0">
  73.       <ttl>
  74.         <xsl:value-of select="$_updateFrequencyNum * $_updatePeriodNum" />
  75.       </ttl>
  76.     </xsl:if>
  77.   </xsl:template>
  78.  
  79. <!-- Convert author strings to Atom format (very simple implementation) -->
  80.   <!-- NOTE: Assumes that value has been properly scrubbed and only needs to be parsed -->
  81.   <xsl:template name="_ConvertAuthorToAtomAuthor">
  82.     <xsl:param name="value" />
  83.     <xsl:if test="string($value)">
  84.       <atom:author>
  85.         <xsl:choose>
  86.           <!-- No email -->
  87.           <xsl:when test="contains($value, '@') = false">
  88.             <atom:name><xsl:value-of select="$value" /></atom:name>
  89.           </xsl:when>
  90.           <!-- Name and email -->
  91.           <xsl:when test="contains($value, '(') and contains($value, ')')">
  92.             <xsl:variable name="_BeforeOpenParen" select="substring-before($value, '(')" />
  93.             <xsl:variable name="_AfterCloseParen" select="substring-after($value, ')')" />
  94.             <xsl:variable name="_WithinParens" select="substring-after(substring-before($value, ')'), '(')" />
  95.             <xsl:choose>
  96.               <!-- Simple check for some possible weird cases -->
  97.               <xsl:when test="contains($_BeforeOpenParen, ')') or contains($_AfterCloseParen, '(') or contains($_WithinParens, '(')">
  98.                 <atom:name><xsl:value-of select="$value" /></atom:name>
  99.               </xsl:when>
  100.               <!-- Email within parens -->
  101.               <xsl:when test="contains($_WithinParens, '@')">
  102.                 <atom:name><xsl:value-of select="concat($_BeforeOpenParen, $_AfterCloseParen)" /></atom:name>
  103.                 <atom:email><xsl:value-of select="$_WithinParens" /></atom:email>
  104.               </xsl:when>
  105.               <!-- Name within parens -->
  106.               <xsl:otherwise>
  107.                 <atom:name><xsl:value-of select="$_WithinParens" /></atom:name>
  108.                 <xsl:choose>
  109.                   <!-- Email before parens -->
  110.                   <xsl:when test="contains($_BeforeOpenParen, '@')">
  111.                     <atom:email><xsl:value-of select="$_BeforeOpenParen" /></atom:email>
  112.                   </xsl:when>
  113.                   <!-- Email after parens -->
  114.                   <xsl:otherwise>
  115.                     <atom:email><xsl:value-of select="$_AfterCloseParen" /></atom:email>
  116.                   </xsl:otherwise>
  117.                 </xsl:choose>
  118.               </xsl:otherwise>
  119.             </xsl:choose>
  120.           </xsl:when>
  121.           <!-- Only email -->
  122.           <xsl:otherwise>
  123.             <atom:email><xsl:value-of select="$value" /></atom:email>
  124.           </xsl:otherwise>
  125.         </xsl:choose>
  126.       </atom:author>
  127.     </xsl:if>
  128.   </xsl:template>
  129.  
  130. <!-- Convert Atom author strings to RSS 2.0 format with email and name -->
  131.   <xsl:template name="_ConvertAtomAuthorToAuthor">
  132.     <xsl:param name="name" />
  133.     <xsl:param name="email" />
  134.     <xsl:choose>
  135.       <xsl:when test="string($name) and string($email)"><xsl:value-of select="concat($email, ' (', $name, ')')" /></xsl:when>
  136.       <xsl:when test="string($email)"><xsl:value-of select="string($email)" /></xsl:when>
  137.       <xsl:otherwise><xsl:value-of select="string($name)" /></xsl:otherwise>
  138.     </xsl:choose>
  139.   </xsl:template>
  140.   
  141. <!-- Map type values to Atom 1.0 type -->
  142. <!-- Note that our sanitization code can parse but cannot output XHTML, so xhtml gets converted to html -->
  143.   <xsl:template name="_NormalizeAtomTextTypeAttr">
  144.     <xsl:param name="value" />
  145.     <xsl:choose>
  146.       <xsl:when test="not(string($value)) or normalize-space($value) = ''"><xsl:attribute name="type">text</xsl:attribute></xsl:when>
  147.       <xsl:when test="$value = 'text/plain' or $value = 'text'"><xsl:attribute name="type">text</xsl:attribute></xsl:when>
  148.       <xsl:when test="$value = 'text/html' or $value = 'html'"><xsl:attribute name="type">html</xsl:attribute></xsl:when>
  149.       <xsl:when test="$value = 'application/xhtml+xml' or $value = 'xhtml'"><xsl:attribute name="type">html</xsl:attribute></xsl:when>
  150.     </xsl:choose>
  151.   </xsl:template>
  152.  
  153. <!-- Validate bool -->
  154.   <xsl:template name="_ValidateBool">
  155.     <xsl:param name="value" />
  156.     <xsl:choose>
  157.       <xsl:when test="normalize-space($value) = 'true'">true</xsl:when>
  158.       <xsl:when test="normalize-space($value) = 'false'">false</xsl:when>
  159.     </xsl:choose>
  160.   </xsl:template>
  161.  
  162. <!-- Build a list of nodes that are referenced from the cf:sort or cf:group -->
  163.   <xsl:template name="_BuildCfReferenceList">
  164.     <xsl:param name="value" />
  165.     <!-- We format the node references as "'namespace-uri':local-name;" -->
  166.     <xsl:for-each select="$value/cf:listinfo/cf:sort">
  167.       <xsl:choose>
  168.         <xsl:when test="@element">'<xsl:value-of select="@ns"/>':<xsl:value-of select="@element" />;</xsl:when>
  169.         <xsl:otherwise>'<xsl:value-of select="@ns"/>':<xsl:value-of select="@label" />;</xsl:otherwise>
  170.       </xsl:choose>
  171.     </xsl:for-each>
  172.     <xsl:for-each select="$value/cf:listinfo/cf:group">
  173.       <xsl:choose>
  174.         <xsl:when test="@element">'<xsl:value-of select="@ns"/>':<xsl:value-of select="@element" />;</xsl:when>
  175.         <xsl:otherwise>'<xsl:value-of select="@ns"/>':<xsl:value-of select="@label" />;</xsl:otherwise>
  176.       </xsl:choose>
  177.     </xsl:for-each>
  178.   </xsl:template>
  179.  
  180. <!-- Ensure XHTML is the default namespace; needs to run prior to sanitization; exact preserving of namespace prefixes
  181. is not important because sanitization will drop all the unknown elements anyway -->
  182.   <xsl:template name="_NormalizeXhtmlNamespacePrefix">
  183.     <xsl:param name="value" />
  184.     <xsl:for-each select="$value">
  185.       <xsl:choose>
  186.         <xsl:when test="self::text() or self::comment() or self::processing-instruction()">
  187.           <xsl:copy />
  188.         </xsl:when>
  189.         <!-- xhtml is default namespace: just copy and process children -->
  190.         <xsl:when test="namespace-uri(.) = $_NSxhtml and not(contains(name(.), ':'))">
  191.           <xsl:copy>
  192.             <xsl:for-each select="@*"><xsl:copy /></xsl:for-each>
  193.             <xsl:call-template name="_NormalizeXhtmlNamespacePrefix">
  194.               <xsl:with-param name="value" select="*|text()" />
  195.             </xsl:call-template>
  196.           </xsl:copy>
  197.         </xsl:when>
  198.         <xsl:otherwise>
  199.           <xsl:choose>
  200.             <!-- xhtml element in non-default namespace: fix namespace and process children -->
  201.             <xsl:when test="namespace-uri(.) = $_NSxhtml">
  202.               <xsl:element name="{local-name(.)}" namespace="{$_NSxhtml}">
  203.                 <xsl:for-each select="@*"><xsl:copy /></xsl:for-each>
  204.                 <xsl:call-template name="_NormalizeXhtmlNamespacePrefix">
  205.                   <xsl:with-param name="value" select="*|text()" />
  206.                 </xsl:call-template>
  207.               </xsl:element>
  208.             </xsl:when>
  209.             <!-- non-xhtml element in default namespace: fix namespace and process children -->
  210.             <xsl:otherwise>
  211.               <xsl:element name="{concat('x:', local-name(.))}" namespace="{namespace-uri(.)}">
  212.                 <xsl:for-each select="@*"><xsl:copy /></xsl:for-each>
  213.                 <xsl:call-template name="_NormalizeXhtmlNamespacePrefix">
  214.                   <xsl:with-param name="value" select="*|text()" />
  215.                 </xsl:call-template>
  216.               </xsl:element>
  217.             </xsl:otherwise>
  218.           </xsl:choose>
  219.         </xsl:otherwise>
  220.       </xsl:choose>
  221.     </xsl:for-each>
  222.   </xsl:template>
  223.  
  224. <!-- Combine base and relative URLs -->
  225.   <xsl:template name="_CombineUrls">
  226.     <xsl:param name="baseUrl" />
  227.     <xsl:param name="relUrl" />
  228.     <xsl:choose>
  229.       <xsl:when test="string($baseUrl)">
  230.         <xsl:value-of select="msfeednorm:CombineUrls(string($baseUrl), string($relUrl))"/>
  231.       </xsl:when>
  232.       <xsl:otherwise>
  233.         <xsl:value-of select="string($relUrl)"/>
  234.       </xsl:otherwise>
  235.     </xsl:choose>
  236.   </xsl:template>
  237.  
  238. <!-- Check for URL and combine it with base (complete the URL) -->
  239.   <xsl:template name="_CompleteUrl">
  240.     <xsl:param name="Url" />
  241.     <xsl:param name="baseUrl" />
  242.     <xsl:if test="string($Url)">
  243.       <xsl:value-of select="msfeednorm:CombineUrls(string($baseUrl), string($Url))"/>
  244.     </xsl:if>
  245.   </xsl:template>
  246.  
  247. <!-- Complete URL in order: baseUrl1 + baseUrl2 + Url -->
  248.   <xsl:template name="_CompleteUrlTwoBase">
  249.     <xsl:param name="Url" />
  250.     <xsl:param name="baseUrl1" />
  251.     <xsl:param name="baseUrl2" />
  252.     <xsl:variable name="combinedBase">
  253.       <xsl:call-template name="_CombineUrls">
  254.         <xsl:with-param name="baseUrl" select="$baseUrl1" />
  255.         <xsl:with-param name="relUrl" select="$baseUrl2" />
  256.       </xsl:call-template>
  257.     </xsl:variable>
  258.     <xsl:call-template name="_CompleteUrl">
  259.       <xsl:with-param name="Url" select="$Url" />
  260.       <xsl:with-param name="baseUrl" select="$combinedBase" />
  261.     </xsl:call-template>
  262.   </xsl:template>
  263.  
  264. <!-- Figure out the base URL for the feed -->
  265.   <xsl:template name="_GetFeedBaseUrl">
  266.     <xsl:param name="downloadUrl" />
  267.     <xsl:param name="rootNode" />
  268.     <xsl:choose>
  269.       <xsl:when test="string($rootNode/@xml:base)">
  270.         <xsl:call-template name="_CombineUrls">
  271.           <xsl:with-param name="baseUrl" select="$downloadUrl" />
  272.           <xsl:with-param name="relUrl" select="$rootNode/@xml:base" />
  273.         </xsl:call-template>
  274.       </xsl:when>
  275.       <xsl:otherwise>
  276.         <xsl:value-of select="string($downloadUrl)" />
  277.       </xsl:otherwise>
  278.     </xsl:choose>
  279.   </xsl:template>
  280.  
  281.  
  282. <!--
  283. Sanitization and validation templates
  284. -->
  285.  
  286. <!-- Invoke sanitization and/or transformation based on the from and to types -->
  287.   <xsl:template name="_CleanByType">
  288.     <xsl:param name="value" />
  289.     <xsl:param name="fromType" />
  290.     <xsl:param name="toType" />
  291.     <xsl:param name="baseUrl" />
  292.     <xsl:variable name="fromTypeN" select="normalize-space($fromType)" />
  293.     <xsl:variable name="toTypeN" select="normalize-space($toType)" />
  294.     <xsl:choose>
  295.       <xsl:when test="not(string($fromTypeN)) or $fromTypeN = 'text' or $fromTypeN = 'text/plain'">
  296.         <xsl:choose>
  297.           <!-- text->text: just copy -->
  298.           <xsl:when test="not(string($toTypeN)) or $toTypeN = 'text' or $toTypeN = 'text/plain'">
  299.             <xsl:value-of select="$value" />
  300.           </xsl:when>
  301.           <!-- text->html: escape -->
  302.           <xsl:when test="$toTypeN = 'html' or $toTypeN = 'text/html'">
  303.             <xsl:value-of select="msfeednorm:HtmlEscape(string($value))" />
  304.           </xsl:when>
  305.         </xsl:choose>
  306.       </xsl:when>
  307.       <xsl:when test="$fromTypeN = 'html' or $fromTypeN = 'text/html'">
  308.         <xsl:choose>
  309.           <!-- html->text: drop all html and unescape -->
  310.           <xsl:when test="not(string($toTypeN)) or $toTypeN = 'text' or $toTypeN = 'text/plain'">
  311.             <xsl:value-of select="msfeednorm:CleanHtmlToPlainText(string($value))" />
  312.           </xsl:when>
  313.           <!-- html->html: drop unsafe html -->
  314.           <xsl:when test="$toTypeN = 'html' or $toTypeN = 'text/html'">
  315.             <xsl:value-of select="msfeednorm:CleanHtmlToSafeHtml(string($baseUrl), string($value))" />
  316.           </xsl:when>
  317.         </xsl:choose>
  318.       </xsl:when>
  319.       <xsl:when test="$fromTypeN = 'xhtml' or $fromTypeN = 'application/xhtml+xml'">
  320.         <xsl:variable name="normXhtml">
  321.           <xsl:call-template name="_NormalizeXhtmlNamespacePrefix">
  322.             <xsl:with-param name="value" select="$value/*" />
  323.           </xsl:call-template>
  324.         </xsl:variable>
  325.         <xsl:choose>
  326.           <!-- xhtml->text: drop all html and unescape -->
  327.           <xsl:when test="not(string($toTypeN)) or $toTypeN = 'text' or $toTypeN = 'text/plain'">
  328.             <xsl:value-of select="msfeednorm:CleanXhtmlToPlainText($normXhtml)" />
  329.           </xsl:when>
  330.           <!-- xhtml->html: drop unsafe html -->
  331.           <xsl:when test="$toTypeN = 'html' or $toTypeN = 'text/html'">
  332.             <xsl:value-of select="msfeednorm:CleanXhtmlToSafeXhtml(string($baseUrl), $normXhtml)" />
  333.           </xsl:when>
  334.         </xsl:choose>
  335.       </xsl:when>
  336.       <!-- Note that any unknown type value will yield empty output -->
  337.     </xsl:choose>
  338.   </xsl:template>
  339.  
  340.  
  341. <!--
  342. Generic output templates
  343. -->
  344.  
  345. <!-- Output attribute with plain text value -->
  346.   <xsl:template name="_OutputTextAttribute">
  347.     <xsl:param name="tagName" />
  348.     <xsl:param name="nameSpace" select="''" />
  349.     <xsl:param name="value" />
  350.     <xsl:variable name="_validatedValue">
  351.       <xsl:call-template name="_CleanByType">
  352.         <xsl:with-param name="value" select="$value" />
  353.         <xsl:with-param name="fromType" select="'text'" />
  354.         <xsl:with-param name="toType" select="'text'" />
  355.       </xsl:call-template>
  356.     </xsl:variable>
  357.     <xsl:if test="string($_validatedValue)">
  358.       <xsl:attribute name="{$tagName}" namespace="{$nameSpace}"><xsl:value-of select="$_validatedValue" /></xsl:attribute>
  359.     </xsl:if>
  360.   </xsl:template>
  361.   
  362. <!-- Output attribute with bool value -->
  363.   <xsl:template name="_OutputBoolAttribute">
  364.     <xsl:param name="tagName" />
  365.     <xsl:param name="nameSpace" select="''" />
  366.     <xsl:param name="value" />
  367.     <xsl:variable name="_validatedValue">
  368.       <xsl:call-template name="_ValidateBool"><xsl:with-param name="value" select="$value" /></xsl:call-template>
  369.     </xsl:variable>
  370.     <xsl:if test="string($_validatedValue)">
  371.       <xsl:attribute name="{$tagName}" namespace="{$nameSpace}"><xsl:value-of select="$_validatedValue" /></xsl:attribute>
  372.     </xsl:if>
  373.   </xsl:template>
  374.  
  375. <!-- Output attribute with URL value -->
  376.   <xsl:template name="_OutputUrlAttribute">
  377.     <xsl:param name="tagName" />
  378.     <xsl:param name="nameSpace" select="''" />
  379.     <xsl:param name="value" />
  380.     <xsl:variable name="_validatedValue" select="msfeednorm:ValidateUrl(normalize-space($value))" />
  381.     <xsl:if test="string($_validatedValue)">
  382.       <xsl:attribute name="{$tagName}" namespace="{$nameSpace}"><xsl:value-of select="$_validatedValue" /></xsl:attribute>
  383.     </xsl:if>
  384.   </xsl:template>
  385.   
  386.   <xsl:template name="_OutputUriAttribute">
  387.     <xsl:param name="tagName" />
  388.     <xsl:param name="nameSpace" select="''" />
  389.     <xsl:param name="value" />
  390.     <xsl:variable name="_validatedValue" select="msfeednorm:NormalizeUri(normalize-space($value))" />
  391.     <xsl:if test="string($_validatedValue)">
  392.       <xsl:attribute name="{$tagName}" namespace="{$nameSpace}"><xsl:value-of select="$_validatedValue" /></xsl:attribute>
  393.     </xsl:if>
  394.   </xsl:template>
  395.  
  396. <!-- Output attribute with mime-type value -->
  397.   <xsl:template name="_OutputMimeTypeAttribute">
  398.     <xsl:param name="tagName" />
  399.     <xsl:param name="nameSpace" select="''" />
  400.     <xsl:param name="value" />
  401.     <xsl:variable name="_validatedValue" select="normalize-space($value)" />
  402.     <xsl:if test="string($_validatedValue)">
  403.       <xsl:attribute name="{$tagName}" namespace="{$nameSpace}"><xsl:value-of select="$_validatedValue" /></xsl:attribute>
  404.     </xsl:if>
  405.   </xsl:template>
  406.  
  407. <!-- Output attribute with non-negative number value -->
  408.   <xsl:template name="_OutputPositiveNumberAttribute">
  409.     <xsl:param name="tagName" />
  410.     <xsl:param name="nameSpace" select="''" />
  411.     <xsl:param name="value" />
  412.     <xsl:variable name="_validatedValue" select="number($value)" />
  413.     <xsl:if test="(string($_validatedValue) != 'NaN') and ($_validatedValue >= 0)">
  414.       <xsl:attribute name="{$tagName}" namespace="{$nameSpace}"><xsl:value-of select="$_validatedValue" /></xsl:attribute>
  415.     </xsl:if>
  416.   </xsl:template>
  417.  
  418. <!-- Output element with plain text value -->
  419.   <xsl:template name="_OutputTextElement">
  420.     <xsl:param name="tagName" />
  421.     <xsl:param name="nameSpace" select="''" />
  422.     <xsl:param name="value" />
  423.     <xsl:param name="type" select="'text'" />
  424.     <xsl:param name="outputTypeAttribute" select="'false'" />
  425.     <xsl:variable name="_validatedValue">
  426.       <xsl:call-template name="_CleanByType">
  427.         <xsl:with-param name="value" select="$value" />
  428.         <xsl:with-param name="fromType" select="$type" />
  429.         <xsl:with-param name="toType" select="'text'" />
  430.       </xsl:call-template>
  431.     </xsl:variable>
  432.     <xsl:if test="string($_validatedValue)">
  433.       <xsl:element name="{$tagName}" namespace="{$nameSpace}">
  434.         <xsl:if test="$outputTypeAttribute = 'true'">
  435.           <xsl:attribute name="cf:type" namespace="{$_NScf}">text</xsl:attribute>
  436.         </xsl:if>
  437.         <xsl:value-of select="$_validatedValue" />
  438.       </xsl:element>
  439.     </xsl:if>
  440.   </xsl:template>
  441.  
  442. <!-- Output element with URL value -->
  443.   <xsl:template name="_OutputUrlElement">
  444.     <xsl:param name="tagName" />
  445.     <xsl:param name="nameSpace" select="''" />
  446.     <xsl:param name="value" />
  447.     <xsl:variable name="_validatedValue" select="msfeednorm:ValidateUrl(normalize-space($value))" />
  448.     <xsl:if test="string($_validatedValue)">
  449.       <xsl:element name="{$tagName}" namespace="{$nameSpace}"><xsl:value-of select="$_validatedValue" /></xsl:element>
  450.     </xsl:if>
  451.   </xsl:template>
  452.  
  453. <!-- Output element with inet date value -->
  454.   <xsl:template name="_OutputDateElement">
  455.     <xsl:param name="tagName" />
  456.     <xsl:param name="nameSpace" select="''" />
  457.     <xsl:param name="value" />
  458.     <xsl:param name="outFormat" select="'inetDate'" />
  459.     <xsl:variable name="_validatedValue">
  460.       <xsl:choose>
  461.         <xsl:when test="$outFormat = 'inetDate'">
  462.           <xsl:value-of select="msfeednorm:NormalizeDateToInetDate(normalize-space($value))"/>
  463.         </xsl:when>
  464.         <xsl:when test="$outFormat = 'iso8601'">
  465.           <xsl:value-of select="msfeednorm:NormalizeDateToIso8601(normalize-space($value))"/>
  466.         </xsl:when>
  467.       </xsl:choose>
  468.     </xsl:variable>
  469.     <xsl:if test="string($_validatedValue)">
  470.       <xsl:element name="{$tagName}" namespace="{$nameSpace}"><xsl:value-of select="$_validatedValue" /></xsl:element>
  471.     </xsl:if>
  472.   </xsl:template>
  473.  
  474. <!-- Output element with a non-negative number value -->
  475.   <xsl:template name="_OutputPositiveNumberElement">
  476.     <xsl:param name="tagName" />
  477.     <xsl:param name="nameSpace" select="''" />
  478.     <xsl:param name="value" />
  479.     <xsl:variable name="_validatedValue" select="number($value)" />
  480.     <xsl:if test="(string($_validatedValue) != 'NaN') and ($_validatedValue >= 0)">
  481.       <xsl:element name="{$tagName}" namespace="{$nameSpace}"><xsl:value-of select="$_validatedValue" /></xsl:element>
  482.     </xsl:if>
  483.   </xsl:template>
  484.   
  485. <!-- Output RSS 2.0 author or managingEditor element and convert into atom:author -->
  486.   <xsl:template name="_OutputAuthorOrEditor">
  487.     <xsl:param name="tagName" />
  488.     <xsl:param name="value" />
  489.     <xsl:param name="convertToAtom" select="'false'" />
  490.     <xsl:variable name="_validatedValue" select="normalize-space($value)" />
  491.     <xsl:if test="string($_validatedValue)">
  492.       <xsl:element name="{$tagName}"><xsl:value-of select="$_validatedValue" /></xsl:element>
  493.       <xsl:if test="$convertToAtom = 'true'">
  494.         <xsl:call-template name="_ConvertAuthorToAtomAuthor"><xsl:with-param name="value" select="$_validatedValue" /></xsl:call-template>
  495.       </xsl:if>
  496.     </xsl:if>
  497.   </xsl:template>
  498.   
  499. <!-- Output atom:author or atom:contributor (have identical handling) -->
  500.   <xsl:template name="_OutputAtomAuthorOrContributor">
  501.     <xsl:param name="tagName" />
  502.     <xsl:param name="name" />
  503.     <xsl:param name="email" />
  504.     <xsl:param name="uri" />
  505.     <xsl:variable name="_validatedName" select="normalize-space($name)" />
  506.     <xsl:variable name="_validatedEmail" select="normalize-space($email)" />
  507.     <xsl:if test="string($_validatedName) or string($_validatedEmail)">
  508.       <xsl:element name="{$tagName}" namespace="{$_NSatom1}">
  509.         <xsl:if test="string($_validatedName)">
  510.           <atom:name><xsl:value-of select="$_validatedName" /></atom:name>
  511.         </xsl:if>
  512.         <xsl:if test="string($_validatedEmail)">
  513.           <atom:email><xsl:value-of select="$_validatedEmail" /></atom:email>
  514.         </xsl:if>
  515.         <xsl:variable name="_validatedUri" select="msfeednorm:NormalizeUri(normalize-space($uri))" />
  516.         <xsl:if test="string($_validatedUri)">
  517.           <atom:uri><xsl:value-of select="$_validatedUri" /></atom:uri>
  518.         </xsl:if>
  519.       </xsl:element>
  520.     </xsl:if>
  521.   </xsl:template>
  522.  
  523.  
  524.  
  525. <!--
  526. Common feed format output templates
  527. -->
  528.  
  529. <!-- xml:lang -->
  530.   <xsl:template name="_OutputXmlLang">
  531.     <xsl:param name="value" />
  532.     <xsl:call-template name="_OutputTextAttribute">
  533.       <xsl:with-param name="tagName" select="'xml:lang'" />
  534.       <xsl:with-param name="value" select="$value" />
  535.     </xsl:call-template>
  536.   </xsl:template>
  537.   
  538. <!-- xml:base -->
  539.   <xsl:template name="_OutputXmlBase">
  540.     <xsl:param name="value" />
  541.     <xsl:call-template name="_OutputUrlAttribute">
  542.       <xsl:with-param name="tagName" select="'xml:base'" />
  543.       <xsl:with-param name="value" select="$value" />
  544.     </xsl:call-template>
  545.   </xsl:template>
  546.  
  547. <!-- title -->
  548.   <xsl:template name="_OutputTitle">
  549.     <xsl:param name="value" />
  550.     <xsl:param name="type" />
  551.     <xsl:call-template name="_OutputTextElement">
  552.       <xsl:with-param name="tagName" select="'title'" />
  553.       <xsl:with-param name="value" select="$value" />
  554.       <xsl:with-param name="type" select="$type" />
  555.       <xsl:with-param name="outputTypeAttribute" select="'true'" />
  556.     </xsl:call-template>
  557.   </xsl:template>
  558.  
  559. <!-- link -->
  560.   <xsl:template name="_OutputLink">
  561.     <xsl:param name="value" />
  562.     <xsl:call-template name="_OutputUrlElement">
  563.       <xsl:with-param name="tagName" select="'link'" />
  564.       <xsl:with-param name="value" select="$value" />
  565.     </xsl:call-template>
  566.   </xsl:template>
  567.  
  568. <!-- plain-text description -->
  569.   <xsl:template name="_OutputTextDescription">
  570.     <xsl:param name="value" />
  571.     <xsl:param name="type" />
  572.     <xsl:call-template name="_OutputTextElement">
  573.       <xsl:with-param name="tagName" select="'description'" />
  574.       <xsl:with-param name="value" select="$value" />
  575.       <xsl:with-param name="type" select="$type" />
  576.       <xsl:with-param name="outputTypeAttribute" select="'true'" />
  577.     </xsl:call-template>
  578.   </xsl:template>
  579.  
  580. <!-- pubDate -->
  581.   <xsl:template name="_OutputPubDate">
  582.     <xsl:param name="value" />
  583.     <xsl:call-template name="_OutputDateElement">
  584.       <xsl:with-param name="tagName" select="'pubDate'" />
  585.       <xsl:with-param name="value" select="$value" />
  586.     </xsl:call-template>
  587.   </xsl:template>
  588.  
  589. <!-- language -->
  590.   <xsl:template name="_OutputLanguage">
  591.     <xsl:param name="value" />
  592.     <xsl:call-template name="_OutputTextElement">
  593.       <xsl:with-param name="tagName" select="'language'" />
  594.       <xsl:with-param name="value" select="$value" />
  595.     </xsl:call-template>
  596.   </xsl:template>
  597.  
  598. <!-- copyright -->
  599.   <xsl:template name="_OutputCopyright">
  600.     <xsl:param name="value" />
  601.     <xsl:param name="type" />
  602.     <xsl:call-template name="_OutputTextElement">
  603.       <xsl:with-param name="tagName" select="'copyright'" />
  604.       <xsl:with-param name="value" select="$value" />
  605.       <xsl:with-param name="type" select="$type" />
  606.       <xsl:with-param name="outputTypeAttribute" select="'true'" />
  607.     </xsl:call-template>
  608.   </xsl:template>
  609.  
  610. <!-- lastBuildDate -->
  611.   <xsl:template name="_OutputLastBuildDate">
  612.     <xsl:param name="value" />
  613.     <xsl:call-template name="_OutputDateElement">
  614.       <xsl:with-param name="tagName" select="'lastBuildDate'" />
  615.       <xsl:with-param name="value" select="$value" />
  616.     </xsl:call-template>
  617.   </xsl:template>
  618.  
  619. <!-- managingEditor -->
  620.   <xsl:template name="_OutputManagingEditor">
  621.     <xsl:param name="value" />
  622.     <xsl:param name="convertToAtom" select="'false'" />
  623.     <xsl:call-template name="_OutputAuthorOrEditor">
  624.       <xsl:with-param name="tagName" select="'managingEditor'" />
  625.       <xsl:with-param name="value" select="$value" />
  626.       <xsl:with-param name="convertToAtom" select="$convertToAtom" />
  627.     </xsl:call-template>
  628.   </xsl:template>
  629.  
  630. <!-- webMaster -->
  631.   <xsl:template name="_OutputWebMaster">
  632.     <xsl:param name="value" />
  633.     <xsl:call-template name="_OutputTextElement">
  634.       <xsl:with-param name="tagName" select="'webMaster'" />
  635.       <xsl:with-param name="value" select="$value" />
  636.     </xsl:call-template>
  637.   </xsl:template>
  638.  
  639. <!-- category -->
  640.   <xsl:template name="_OutputCategory">
  641.     <xsl:param name="value" />
  642.     <xsl:param name="domain" />
  643.     <xsl:variable name="_validatedValue" select="normalize-space($value)" />
  644.     <xsl:if test="string($_validatedValue)">
  645.       <xsl:element name="category">
  646.         <xsl:call-template name="_OutputTextAttribute">
  647.           <xsl:with-param name="tagName" select="'domain'" />
  648.           <xsl:with-param name="value" select="$domain" />
  649.         </xsl:call-template>
  650.         <xsl:value-of select="$_validatedValue" />
  651.       </xsl:element>
  652.     </xsl:if>
  653.   </xsl:template>
  654.  
  655. <!-- generator -->
  656.   <xsl:template name="_OutputGenerator">
  657.     <xsl:param name="value" />
  658.     <xsl:param name="uri" />
  659.     <xsl:param name="version" />
  660.     <xsl:variable name="_validatedValue" select="normalize-space($value)" />
  661.     <xsl:if test="string($_validatedValue)">
  662.       <xsl:element name="generator">
  663.         <xsl:call-template name="_OutputUriAttribute">
  664.           <xsl:with-param name="tagName" select="'cf:uri'" />
  665.           <xsl:with-param name="nameSpace" select="$_NScf" />
  666.           <xsl:with-param name="value" select="$uri" />
  667.         </xsl:call-template>
  668.         <xsl:call-template name="_OutputTextAttribute">
  669.           <xsl:with-param name="tagName" select="'cf:version'" />
  670.           <xsl:with-param name="nameSpace" select="$_NScf" />
  671.           <xsl:with-param name="value" select="$version" />
  672.         </xsl:call-template>
  673.         <xsl:value-of select="$_validatedValue" />
  674.       </xsl:element>
  675.     </xsl:if>
  676.   </xsl:template>
  677.  
  678. <!-- docs -->
  679.   <xsl:template name="_OutputDocs">
  680.     <xsl:param name="value" />
  681.     <xsl:call-template name="_OutputUrlElement">
  682.       <xsl:with-param name="tagName" select="'docs'" />
  683.       <xsl:with-param name="value" select="$value" />
  684.     </xsl:call-template>
  685.   </xsl:template>
  686.  
  687. <!-- cloud -->
  688.   <xsl:template name="_OutputCloud">
  689.     <xsl:param name="value" />
  690.     <!-- We always output this element and clean any attribute it has into text -->
  691.     <cloud>
  692.       <xsl:for-each select="$value/@*">
  693.         <xsl:attribute name="{name(.)}"><xsl:value-of select="normalize-space(.)"/></xsl:attribute>
  694.       </xsl:for-each>
  695.     </cloud>
  696.   </xsl:template>
  697.  
  698. <!-- ttl -->
  699.   <xsl:template name="_OutputTtl">
  700.     <xsl:param name="value" />
  701.     <xsl:call-template name="_OutputPositiveNumberElement">
  702.       <xsl:with-param name="tagName" select="'ttl'" />
  703.       <xsl:with-param name="value" select="$value" />
  704.     </xsl:call-template>
  705.   </xsl:template>
  706.  
  707. <!-- image -->
  708.   <xsl:template name="_OutputImage">
  709.     <xsl:param name="url" />
  710.     <xsl:param name="title" />
  711.     <xsl:param name="titleType" select="'text'" />
  712.     <xsl:param name="link" />
  713.     <xsl:param name="width" />
  714.     <xsl:param name="height" />
  715.     <xsl:param name="description" />
  716.     <xsl:param name="subnodesToCopy" />
  717.     <xsl:variable name="_validatedUrl" select="msfeednorm:ValidateUrl(normalize-space($url))" />
  718.     <xsl:if test="string($_validatedUrl)">
  719.       <image>
  720.         <url><xsl:value-of select="$_validatedUrl" /></url>
  721.         <xsl:call-template name="_OutputTextElement">
  722.           <xsl:with-param name="tagName" select="'title'" />
  723.           <xsl:with-param name="value" select="$title" />
  724.           <xsl:with-param name="type" select="$titleType" />
  725.         </xsl:call-template>
  726.         <xsl:call-template name="_OutputUrlElement">
  727.           <xsl:with-param name="tagName" select="'link'" />
  728.           <xsl:with-param name="value" select="$link" />
  729.         </xsl:call-template>
  730.         <xsl:call-template name="_OutputPositiveNumberElement">
  731.           <xsl:with-param name="tagName" select="'width'" />
  732.           <xsl:with-param name="value" select="$width" />
  733.         </xsl:call-template>
  734.         <xsl:call-template name="_OutputPositiveNumberElement">
  735.           <xsl:with-param name="tagName" select="'height'" />
  736.           <xsl:with-param name="value" select="$height" />
  737.         </xsl:call-template>
  738.         <xsl:call-template name="_OutputTextElement">
  739.           <xsl:with-param name="tagName" select="'description'" />
  740.           <xsl:with-param name="value" select="$description" />
  741.         </xsl:call-template>
  742.         <xsl:if test="boolean($subnodesToCopy)">
  743.           <xsl:for-each select="$subnodesToCopy">
  744.             <xsl:copy-of select="." />
  745.           </xsl:for-each>
  746.         </xsl:if>
  747.       </image>
  748.     </xsl:if>
  749.   </xsl:template>
  750.  
  751. <!-- rating -->
  752.   <xsl:template name="_OutputRating">
  753.     <xsl:param name="value" />
  754.     <xsl:call-template name="_OutputTextElement">
  755.       <xsl:with-param name="tagName" select="'rating'" />
  756.       <xsl:with-param name="value" select="$value" />
  757.     </xsl:call-template>
  758.   </xsl:template>
  759.  
  760. <!-- textInput -->
  761.   <xsl:template name="_OutputTextInput">
  762.     <xsl:param name="title" />
  763.     <xsl:param name="name" />
  764.     <xsl:param name="link" />
  765.     <xsl:param name="description" />
  766.     <xsl:param name="subnodesToCopy" />
  767.     <xsl:variable name="_validatedName" select="normalize-space($name)" />
  768.     <xsl:variable name="_validatedLink" select="msfeednorm:ValidateUrl(normalize-space($link))" />
  769.     <xsl:if test="string($_validatedName) and string($_validatedLink)">
  770.       <textInput>
  771.         <name><xsl:value-of select="$_validatedName" /></name>
  772.         <link><xsl:value-of select="$_validatedLink" /></link>
  773.         <xsl:call-template name="_OutputTextElement">
  774.           <xsl:with-param name="tagName" select="'title'" />
  775.           <xsl:with-param name="value" select="$title" />
  776.         </xsl:call-template>
  777.         <xsl:call-template name="_OutputTextElement">
  778.           <xsl:with-param name="tagName" select="'description'" />
  779.           <xsl:with-param name="value" select="$description" />
  780.         </xsl:call-template>
  781.         <xsl:if test="boolean($subnodesToCopy)">
  782.           <xsl:for-each select="$subnodesToCopy">
  783.             <xsl:copy-of select="." />
  784.           </xsl:for-each>
  785.         </xsl:if>
  786.       </textInput>
  787.     </xsl:if>
  788.   </xsl:template>
  789.  
  790. <!-- skipHours -->
  791.   <xsl:template name="_OutputSkipHours">
  792.     <xsl:param name="value" />
  793.     <xsl:if test="$value/hour[number(.)>=0 and number(.)<=23]">
  794.       <skipHours>
  795.         <xsl:for-each select="$value/hour">
  796.           <xsl:variable name="_numberHour" select="number(.)" />
  797.           <xsl:if test="$_numberHour >= 0 and $_numberHour <= 23">
  798.             <hour><xsl:value-of select="$_numberHour" /></hour>
  799.           </xsl:if>
  800.         </xsl:for-each>
  801.       </skipHours>
  802.     </xsl:if>
  803.   </xsl:template>
  804.  
  805. <!-- skipDays -->
  806.   <xsl:template name="_OutputSkipDays">
  807.     <xsl:param name="value" />
  808.     <xsl:if test="$value/day[string(.) = 'Monday' or string(.) = 'Tuesday' or string(.) = 'Wednesday' or string(.) = 'Thursday' or string(.) = 'Friday' or string(.) = 'Saturday' or string(.) = 'Sunday']">
  809.       <skipDays>
  810.         <xsl:for-each select="$value/day">
  811.           <xsl:variable name="_stringDay" select="string(.)" />
  812.           <xsl:if test="$_stringDay = 'Monday' or $_stringDay = 'Tuesday' or $_stringDay = 'Wednesday' or $_stringDay = 'Thursday' or $_stringDay = 'Friday' or $_stringDay = 'Saturday' or $_stringDay = 'Sunday'">
  813.             <day><xsl:value-of select="$_stringDay" /></day>
  814.           </xsl:if>
  815.         </xsl:for-each>
  816.       </skipDays>
  817.     </xsl:if>
  818.   </xsl:template>
  819.  
  820. <!-- author -->
  821.   <xsl:template name="_OutputAuthor">
  822.     <xsl:param name="value" />
  823.     <xsl:param name="convertToAtom" select="'false'" />
  824.     <xsl:call-template name="_OutputAuthorOrEditor">
  825.       <xsl:with-param name="tagName" select="'author'" />
  826.       <xsl:with-param name="value" select="$value" />
  827.       <xsl:with-param name="convertToAtom" select="$convertToAtom" />
  828.     </xsl:call-template>
  829.   </xsl:template>
  830.  
  831. <!-- comments -->
  832.   <xsl:template name="_OutputComments">
  833.     <xsl:param name="value" />
  834.     <xsl:call-template name="_OutputUrlElement">
  835.       <xsl:with-param name="tagName" select="'comments'" />
  836.       <xsl:with-param name="value" select="$value" />
  837.     </xsl:call-template>
  838.   </xsl:template>
  839.  
  840. <!-- enclosure -->
  841.   <xsl:template name="_OutputEnclosure">
  842.     <xsl:param name="url" />
  843.     <xsl:param name="length" />
  844.     <xsl:param name="type" />
  845.     <xsl:variable name="_validatedUrl" select="msfeednorm:ValidateUrl(normalize-space($url))" />
  846.     <xsl:if test="string($_validatedUrl)">
  847.       <enclosure>
  848.         <xsl:attribute name="url"><xsl:value-of select="$_validatedUrl"/></xsl:attribute>
  849.         <xsl:call-template name="_OutputPositiveNumberAttribute">
  850.           <xsl:with-param name="tagName" select="'length'" />
  851.           <xsl:with-param name="value" select="$length" />
  852.         </xsl:call-template>
  853.         <xsl:call-template name="_OutputMimeTypeAttribute">
  854.           <xsl:with-param name="tagName" select="'type'" />
  855.           <xsl:with-param name="value" select="$type" />
  856.         </xsl:call-template>
  857.       </enclosure>
  858.     </xsl:if>
  859.   </xsl:template>
  860.  
  861. <!-- guid -->
  862.   <xsl:template name="_OutputGuid">
  863.     <xsl:param name="value" />
  864.     <xsl:param name="isPermaLink" />
  865.     <xsl:param name="channelGuid" select="'false'" />
  866.     <xsl:variable name="_validatedValue">
  867.       <xsl:choose>
  868.         <xsl:when test="normalize-space($isPermaLink) = 'true' or not(string($isPermaLink))">
  869.           <xsl:value-of select="msfeednorm:ValidateUrl(normalize-space($value))" />
  870.         </xsl:when>
  871.         <xsl:otherwise>
  872.           <xsl:value-of select="string($value)" />
  873.         </xsl:otherwise>
  874.       </xsl:choose>
  875.     </xsl:variable>
  876.     <xsl:if test="string($_validatedValue)">
  877.       <xsl:choose>
  878.         <xsl:when test="$channelGuid = 'false'">
  879.           <xsl:element name="guid">
  880.             <xsl:call-template name="_OutputBoolAttribute">
  881.               <xsl:with-param name="tagName" select="'isPermaLink'" />
  882.               <xsl:with-param name="value" select="$isPermaLink" />
  883.             </xsl:call-template>
  884.             <xsl:value-of select="$_validatedValue" />
  885.           </xsl:element>
  886.         </xsl:when>
  887.         <xsl:otherwise>
  888.           <xsl:element name="cf:guid" namespace="{$_NScf}">
  889.             <xsl:call-template name="_OutputBoolAttribute">
  890.               <xsl:with-param name="tagName" select="'isPermaLink'" />
  891.               <xsl:with-param name="value" select="$isPermaLink" />
  892.             </xsl:call-template>
  893.             <xsl:value-of select="$_validatedValue" />
  894.           </xsl:element>
  895.         </xsl:otherwise>
  896.       </xsl:choose>
  897.     </xsl:if>
  898.   </xsl:template>
  899.   
  900. <!-- source -->
  901.   <xsl:template name="_OutputSource">
  902.     <xsl:param name="value" />
  903.     <xsl:param name="url" />
  904.     <xsl:variable name="_validatedValue" select="normalize-space($value)" />
  905.     <xsl:if test="string($_validatedValue)">
  906.       <xsl:element name="source">
  907.         <xsl:call-template name="_OutputUrlAttribute">
  908.           <xsl:with-param name="tagName" select="'url'" />
  909.           <xsl:with-param name="value" select="$url" />
  910.         </xsl:call-template>
  911.         <xsl:value-of select="$_validatedValue" />
  912.       </xsl:element>
  913.     </xsl:if>
  914.   </xsl:template>
  915.  
  916. <!-- rich-text description -->
  917.   <xsl:template name="_OutputDescription">
  918.     <xsl:param name="value" />
  919.     <xsl:param name="type" />
  920.     <xsl:param name="baseUrl" />
  921.     <!-- Description is always html -->
  922.     <description cf:type="html">
  923.       <xsl:call-template name="_CleanByType">
  924.         <xsl:with-param name="value" select="$value" />
  925.         <xsl:with-param name="fromType" select="$type" />
  926.         <xsl:with-param name="toType" select="'html'" />
  927.         <xsl:with-param name="baseUrl" select="$baseUrl" />
  928.       </xsl:call-template>
  929.     </description>
  930.   </xsl:template>
  931.  
  932. <!-- atom:summary -->
  933.   <xsl:template name="_OutputAtomSummary">
  934.     <xsl:param name="value" />
  935.     <xsl:param name="type" />
  936.     <xsl:param name="xmlBase" />
  937.     <xsl:param name="baseUrl" />
  938.     <atom:summary>
  939.       <xsl:call-template name="_OutputXmlBase"><xsl:with-param name="value" select="$xmlBase" /></xsl:call-template>
  940.       <xsl:call-template name="_NormalizeAtomTextTypeAttr"><xsl:with-param name="value" select="$type" /></xsl:call-template>
  941.       <xsl:call-template name="_CleanByType">
  942.         <xsl:with-param name="value" select="$value" />
  943.         <xsl:with-param name="fromType" select="$type" />
  944.         <xsl:with-param name="toType" select="$type" />
  945.         <xsl:with-param name="baseUrl" select="$baseUrl" />
  946.       </xsl:call-template>
  947.     </atom:summary>
  948.   </xsl:template>
  949.  
  950. <!-- description and summary (if it exists) -->
  951.   <xsl:template name="_OutputDescriptionAndSummary">
  952.     <xsl:param name="description" />
  953.     <xsl:param name="descriptionType" />
  954.     <xsl:param name="descriptionBaseUrl" />
  955.     <xsl:param name="summary" />
  956.     <xsl:param name="summaryType" />
  957.     <xsl:param name="summaryXmlBase" />
  958.     <xsl:param name="summaryBaseUrl" />
  959.     <xsl:call-template name="_OutputDescription">
  960.       <xsl:with-param name="value" select="$description" />
  961.       <xsl:with-param name="type" select="$descriptionType" />
  962.       <xsl:with-param name="baseUrl" select="$descriptionBaseUrl" />
  963.     </xsl:call-template>
  964.     <xsl:if test="string($summary)">
  965.       <xsl:call-template name="_OutputAtomSummary">
  966.         <xsl:with-param name="value" select="$summary" />
  967.         <xsl:with-param name="type" select="$summaryType" />
  968.         <xsl:with-param name="xmlBase" select="$summaryXmlBase" />
  969.         <xsl:with-param name="baseUrl" select="$summaryBaseUrl" />
  970.       </xsl:call-template>
  971.     </xsl:if>
  972.   </xsl:template>
  973.  
  974. <!-- atom:link -->
  975.   <xsl:template name="_OutputAtomLink">
  976.     <xsl:param name="href" />
  977.     <xsl:param name="rel" />
  978.     <xsl:param name="type" />
  979.     <xsl:param name="title" />
  980.     <xsl:param name="hreflang" />
  981.     <xsl:param name="length" />
  982.     <xsl:param name="xmlBase" />
  983.     <xsl:variable name="_validatedHref" select="msfeednorm:ValidateUrl(normalize-space($href))" />
  984.     <xsl:if test="string($_validatedHref)">
  985.       <atom:link>
  986.         <xsl:attribute name="href"><xsl:value-of select="$_validatedHref" /></xsl:attribute>
  987.         <xsl:call-template name="_OutputTextAttribute">
  988.           <xsl:with-param name="tagName" select="'rel'" />
  989.           <xsl:with-param name="value" select="$rel" />
  990.         </xsl:call-template>
  991.         <xsl:call-template name="_OutputMimeTypeAttribute">
  992.           <xsl:with-param name="tagName" select="'type'" />
  993.           <xsl:with-param name="value" select="$type" />
  994.         </xsl:call-template>
  995.         <xsl:call-template name="_OutputTextAttribute">
  996.           <xsl:with-param name="tagName" select="'title'" />
  997.           <xsl:with-param name="value" select="$title" />
  998.         </xsl:call-template>
  999.         <xsl:call-template name="_OutputTextAttribute">
  1000.           <xsl:with-param name="tagName" select="'hreflang'" />
  1001.           <xsl:with-param name="value" select="$hreflang" />
  1002.         </xsl:call-template>
  1003.         <xsl:call-template name="_OutputPositiveNumberAttribute">
  1004.           <xsl:with-param name="tagName" select="'length'" />
  1005.           <xsl:with-param name="value" select="$length" />
  1006.         </xsl:call-template>
  1007.         <xsl:call-template name="_OutputXmlBase">
  1008.           <xsl:with-param name="value" select="$xmlBase" />
  1009.         </xsl:call-template>
  1010.       </atom:link>
  1011.     </xsl:if>
  1012.   </xsl:template>
  1013.  
  1014. <!-- atom:author -->
  1015.   <xsl:template name="_OutputAtomAuthor">
  1016.     <xsl:param name="name" />
  1017.     <xsl:param name="email" />
  1018.     <xsl:param name="uri" />
  1019.     <xsl:call-template name="_OutputAtomAuthorOrContributor">
  1020.       <xsl:with-param name="tagName" select="'atom:author'" />
  1021.       <xsl:with-param name="name" select="$name" />
  1022.       <xsl:with-param name="email" select="$email" />
  1023.       <xsl:with-param name="uri" select="$uri" />
  1024.     </xsl:call-template>
  1025.   </xsl:template>
  1026.  
  1027. <!-- atom:contributor -->
  1028.   <xsl:template name="_OutputAtomContributor">
  1029.     <xsl:param name="name" />
  1030.     <xsl:param name="email" />
  1031.     <xsl:param name="uri" />
  1032.     <xsl:call-template name="_OutputAtomAuthorOrContributor">
  1033.       <xsl:with-param name="tagName" select="'atom:contributor'" />
  1034.       <xsl:with-param name="name" select="$name" />
  1035.       <xsl:with-param name="email" select="$email" />
  1036.       <xsl:with-param name="uri" select="$uri" />
  1037.     </xsl:call-template>
  1038.   </xsl:template>
  1039.   
  1040. <!-- atom:published -->
  1041.   <xsl:template name="_OutputAtomPublished">
  1042.     <xsl:param name="value" />
  1043.     <xsl:call-template name="_OutputDateElement">
  1044.       <xsl:with-param name="tagName" select="'atom:published'" />
  1045.       <xsl:with-param name="nameSpace" select="$_NSatom1" />
  1046.       <xsl:with-param name="value" select="$value" />
  1047.       <xsl:with-param name="outFormat" select="'iso8601'" />
  1048.     </xsl:call-template>
  1049.   </xsl:template>
  1050.   
  1051. <!-- atom:updated -->
  1052.   <xsl:template name="_OutputAtomUpdated">
  1053.     <xsl:param name="value" />
  1054.     <xsl:call-template name="_OutputDateElement">
  1055.       <xsl:with-param name="tagName" select="'atom:updated'" />
  1056.       <xsl:with-param name="nameSpace" select="$_NSatom1" />
  1057.       <xsl:with-param name="value" select="$value" />
  1058.       <xsl:with-param name="outFormat" select="'iso8601'" />
  1059.     </xsl:call-template>
  1060.   </xsl:template>
  1061.  
  1062. <!-- slash:comments -->
  1063.   <xsl:template name="_OutputSlashComments">
  1064.     <xsl:param name="value" />
  1065.     <xsl:call-template name="_OutputPositiveNumberElement">
  1066.       <xsl:with-param name="tagName" select="'slash:comments'" />
  1067.       <xsl:with-param name="nameSpace" select="$_NSslash" />
  1068.       <xsl:with-param name="value" select="$value" />
  1069.     </xsl:call-template>
  1070.   </xsl:template>
  1071.   
  1072. <!-- wfw:commentRss -->
  1073.   <xsl:template name="_OutputWfwCommentRSS">
  1074.     <xsl:param name="value" />
  1075.     <xsl:call-template name="_OutputUrlElement">
  1076.       <xsl:with-param name="tagName" select="'wfw:commentRss'" />
  1077.       <xsl:with-param name="nameSpace" select="$_NSwfw" />
  1078.       <xsl:with-param name="value" select="$value" />
  1079.     </xsl:call-template>
  1080.   </xsl:template>
  1081.   
  1082. <!-- cf:treatAs -->
  1083.   <xsl:template name="_OutputCfTreatAs">
  1084.     <xsl:param name="value" />
  1085.     <xsl:call-template name="_OutputTextElement">
  1086.       <xsl:with-param name="tagName" select="'cf:treatAs'" />
  1087.       <xsl:with-param name="nameSpace" select="$_NScf" />
  1088.       <xsl:with-param name="value" select="$value" />
  1089.     </xsl:call-template>
  1090.   </xsl:template>
  1091.  
  1092. <!-- cf:listinfo -->
  1093.   <xsl:template name="_OutputCfListinfo">
  1094.     <xsl:param name="value" />
  1095.     <cf:listinfo>
  1096.       <xsl:for-each select="$value/cf:sort">
  1097.         <xsl:variable name="_ValidatedSortElem" select="normalize-space(@element)" />
  1098.         <xsl:variable name="_ValidatedSortLabel" select="normalize-space(@label)" />
  1099.         <xsl:if test="string($_ValidatedSortElem) or string($_ValidatedSortLabel)">
  1100.           <cf:sort>
  1101.             <xsl:if test="string($_ValidatedSortElem)">
  1102.               <xsl:attribute name="element"><xsl:value-of select="$_ValidatedSortElem"/></xsl:attribute>
  1103.             </xsl:if>
  1104.             <xsl:if test="string($_ValidatedSortLabel)">
  1105.               <xsl:attribute name="label"><xsl:value-of select="$_ValidatedSortLabel"/></xsl:attribute>
  1106.             </xsl:if>
  1107.             <xsl:call-template name="_OutputTextAttribute">
  1108.               <xsl:with-param name="tagName" select="'ns'" />
  1109.               <xsl:with-param name="value" select="@ns" />
  1110.             </xsl:call-template>
  1111.             <xsl:call-template name="_OutputTextAttribute">
  1112.               <xsl:with-param name="tagName" select="'data-type'" />
  1113.               <xsl:with-param name="value" select="@data-type" />
  1114.             </xsl:call-template>
  1115.             <xsl:call-template name="_OutputBoolAttribute">
  1116.               <xsl:with-param name="tagName" select="'default'" />
  1117.               <xsl:with-param name="value" select="@default" />
  1118.             </xsl:call-template>
  1119.           </cf:sort>
  1120.         </xsl:if>
  1121.       </xsl:for-each>
  1122.       <xsl:for-each select="$value/cf:group">
  1123.         <xsl:variable name="_ValidatedGroupElem" select="normalize-space(@element)" />
  1124.         <xsl:variable name="_ValidatedGroupLabel" select="normalize-space(@label)" />
  1125.         <xsl:if test="string($_ValidatedGroupElem) or string($_ValidatedGroupLabel)">
  1126.           <cf:group>
  1127.             <xsl:if test="string($_ValidatedGroupElem)">
  1128.               <xsl:attribute name="element"><xsl:value-of select="$_ValidatedGroupElem"/></xsl:attribute>
  1129.             </xsl:if>
  1130.             <xsl:if test="string($_ValidatedGroupLabel)">
  1131.               <xsl:attribute name="label"><xsl:value-of select="$_ValidatedGroupLabel"/></xsl:attribute>
  1132.             </xsl:if>
  1133.             <xsl:call-template name="_OutputTextAttribute">
  1134.               <xsl:with-param name="tagName" select="'ns'" />
  1135.               <xsl:with-param name="value" select="@ns" />
  1136.             </xsl:call-template>
  1137.           </cf:group>
  1138.         </xsl:if>
  1139.       </xsl:for-each>
  1140.     </cf:listinfo>
  1141.   </xsl:template>
  1142.  
  1143. <!-- output the extension nodes -->
  1144.   <xsl:template name="_OutputExtension">
  1145.     <xsl:param name="value" />
  1146.     <xsl:param name="references" />
  1147.     <xsl:if test="namespace-uri($value) != $_NScfi">
  1148.       <xsl:variable name="nodeRefName">'<xsl:value-of select="namespace-uri($value)"/>':<xsl:value-of select="local-name($value)"/>;</xsl:variable>
  1149.       <xsl:choose>
  1150.         <xsl:when test="string($references) and contains($references, $nodeRefName)">
  1151.           <xsl:call-template name="_OutputTextElement">
  1152.             <xsl:with-param name="value" select="$value" />
  1153.             <xsl:with-param name="tagName" select="name($value)" />
  1154.             <xsl:with-param name="nameSpace" select="namespace-uri($value)" />
  1155.           </xsl:call-template>
  1156.         </xsl:when>
  1157.         <xsl:otherwise>
  1158.           <xsl:copy-of select="$value" />
  1159.         </xsl:otherwise>
  1160.       </xsl:choose>
  1161.     </xsl:if>
  1162.   </xsl:template>
  1163.  
  1164. </xsl:stylesheet>
  1165.