使用<section>祖先节点</section>的数量使用HXT转换节点

时间:2014-05-01 21:08:08

标签: xslt haskell arrows hxt

我希望将所有title元素替换为h1h2,...,h6元素,具体取决于祖先的数量section元素。输入/输出示例:

Input.xml文件

<document>
    <section>
        <title>Title A</title>
        <section>
            <title>Title B</title>
        </section>
        <section>
            <title>Title C</title>
            <section>
                <title>Title D</title>
            </section>
        </section>
    </section>
</document>

的Output.xml

<document>
    <section>
        <h1>Title A</h1>
        <section>
            <h2>Title B</h2>
        </section>
        <section>
            <h2>Title C</h2>
            <section>
                <h3>Title D</h3>
            </section>
        </section>
    </section>
</document>

我可以使用类似

title替换所有h1 s
swapTitles :: ArrowXml a => a XmlTree XmlTree
swapTitles = processTopDown $
             (changeQName . const $ mkName "h1")
             `when`
             (isElem >>> (hasQName $ mkName "title"))

我相信我应该使用ArrowState,但我无法弄清楚如何。有人能指出我正确的方向吗?

1 个答案:

答案 0 :(得分:0)

XSL与包hxt-xslt一起使用。标准使生活更轻松: - )

{-# LANGUAGE Arrows, PackageImports #-} 

import System.Environment ( getArgs )
import System.Exit (exitSuccess, exitWith, ExitCode(..))

import Control.Arrow
import "hxt" Text.XML.HXT.Core 
import "hxt" Text.XML.HXT.DOM.XmlKeywords 
import "hxt-xslt" Text.XML.HXT.XSLT.XsltArrows
import "hxt" Text.XML.HXT.Arrow.XmlState.TraceHandling (withTraceLevel)

process :: String -> String -> IO [String]
process xslStylesheetPath xmlDocPath = do

    -- compile stylesheet

    compiledStyleSheetResults <- runX $ 
        arr (const xslStylesheetPath) 
        >>> readXSLTDoc [ withValidate yes, withInputEncoding utf8]   -- withTrace 2 
        >>> {- withTraceLevel 2 -} xsltCompileStylesheet

    case compiledStyleSheetResults of
         [] -> return ["error compiling " ++ xslStylesheetPath] 
         compiledStyleSheet : _ -> do

             -- apply compiled stylesheet to xml doc 

             runX $ arr (const xmlDocPath) 
                 >>> readXSLTDoc [ withValidate yes, withInputEncoding utf8] -- withTrace 2
                 >>> xsltApplyStylesheet compiledStyleSheet
                 >>> writeDocumentToString [withOutputEncoding utf8, 
                                            withXmlPi yes, withIndent yes]

-- readXSLTDoc from internals of module Text.XML.HXT.XSLT.XsltArrows

readXSLTDoc :: SysConfigList -> IOSArrow String XmlTree
readXSLTDoc options
    = readFromDocument (options ++ defaultOptions)
    where
    defaultOptions
        = [ withCheckNamespaces yes
          , withValidate        no
          , withPreserveComment no
          ]         

main = do
 args <- getArgs
 case args of 
   [arg1, arg2] -> do
       results <- process arg1 arg2
       case results of
            [] -> putStrLn "errors"
            result : _ -> putStrLn result

       exitSuccess

   _ -> do 
            putStrLn "missing parameters: xslStylesheetPath xmlDocPath"
            exitWith $ ExitFailure 1

使用XSL文件&#34; mystyle.xsl&#34;

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:template match="/">
  <xsl:for-each select="document">
    <xsl:copy>
      <xsl:call-template name="myloop">
        <xsl:with-param name="nesting" select="0"/>
      </xsl:call-template>
    </xsl:copy>
  </xsl:for-each>
</xsl:template>

<xsl:template name="myloop">
  <xsl:param name="nesting"/>

  <xsl:if test="title">
   <xsl:element name="{concat('h',string($nesting))}">
     <xsl:value-of select="title" /> 
   </xsl:element>
  </xsl:if> 

  <xsl:for-each select="section">
    <xsl:copy>
      <xsl:call-template name="myloop">
        <xsl:with-param name="nesting" select="$nesting+1"/>
      </xsl:call-template>
    </xsl:copy>
  </xsl:for-each>

</xsl:template>
</xsl:stylesheet>

使用&#34; yourdata.xml&#34;

<?xml version="1.0" encoding="UTF-8"?>
<document>
    <section>
        <title>Title A</title>
        <section>
            <title>Title B</title>
        </section>
        <section>
            <title>Title C</title>
            <section>
                <title>Title D</title>
            </section>
        </section>
    </section>
</document>

运行

runhaskell test.hs mystyle.xsl yourdata.xml

结果:

<?xml version="1.0" encoding="UTF-8"?>
<document>
  <section>
    <h1>Title A</h1>
    <section>
      <h2>Title B</h2>
    </section>
    <section>
      <h2>Title C</h2>
      <section>
        <h3>Title D</h3>
      </section>
    </section>
  </section>
</document>