2011-12-09 147 views
3

我想基於輸入文件表達式自動化元素。使用XSLT自動創建xml元素

我輸入文件看起來像

<?xml version="1.0" encoding="UTF-8"?> 
<mappings> 
    <mapping inputContext="InputRoot" outputContext="outputRoot"> 
     <input>InputParent/InputChild/InputSubChild</input> 
     <output>OutputParent/OPChild</output> 
    </mapping> 
</mappings> 

基於上面的XML我創造了以下XSLT

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns="http://www.testmapping.org/mapping"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
    <xsl:template match="/"> 
     <xsl:variable name="outputCtxt" select="mappings/mapping/output"/> 
     <xsl:call-template name="contextGenerator"> 
      <xsl:with-param name="contextPath" select="$outputCtxt"/> 
     </xsl:call-template> 
    </xsl:template> 
    <xsl:template name="contextGenerator"> 
     <xsl:param name="contextPath" as="xs:string?"/> 
     <xsl:variable name="currentContext" select="substring-before($contextPath,'/')"/> 
     <xsl:variable name="subContext" select="substring-after($contextPath,'/')"/> 
     <xsl:element name="{$currentContext}"> 
      <xsl:call-template name="contextGenerator"> 
       <xsl:with-param name="contextPath" select="$subContext"/> 
      </xsl:call-template> 
     </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 

我期待的輸出與以下格式

<outputRoot> 
    <OutputParent> 
     <OPChild></OPChild> 
    </OutputParent> 
</outputRoot> 

當我我正在嘗試根據輸入進行轉換,結果出現了預期的QName錯誤。我能否提出解決此問題的建議?

回答

3

contextGenerator模板未正確分割和遞歸。 (有一個在參數contextGenerator在第二次調用沒有/,所以分裂失敗。)

添加下面的模板可以幫助顯示問題:

<xsl:message> 
    [<xsl:value-of select="$currentContext"/>] 
    [<xsl:value-of select="$subContext"/>] 
</xsl:message> 

輸出:

[OutputParent] 
[OPChild] 
[] 
[] 

以下替換模板會生成正確的輸出:

<xsl:template name="contextGenerator"> 
    <xsl:param name="contextPath" as="xs:string?"/> 
    <xsl:choose> 
     <xsl:when test="contains($contextPath, '/')"> 
      <xsl:element name="{substring-before($contextPath, '/')}"> 
       <xsl:variable name="subContext" 
           select="substring-after($contextPath, '/')"/> 
       <xsl:if test="$subContext"> 
        <xsl:call-template name="contextGenerator"> 
         <xsl:with-param name="contextPath" select="$subContext"/> 
        </xsl:call-template> 
       </xsl:if> 
      </xsl:element> 
     </xsl:when> 
     <xsl:otherwise> 
      <xsl:element name="{$contextPath}"/> 
     </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

結果:

<OutputParent> 
    <OPChild/> 
</OutputParent> 
+0

+1好答案。@OP,你的遞歸模板沒有終止條件,所以如果你沒有得到一個錯誤,你會有一個無限的遞歸(實際上是一個堆棧溢出...) – LarsH

0

在XML中,元素名稱必須符合QNames的詞法結構。您正嘗試創建一個名爲InputParent/InputChild/InputSubChild的元素。這包含QName中不允許的字符(/)。

要解決該錯誤,您可以用_代替/ ...,具體取決於您的要求。

E.g.

<xsl:element name="{replace($currentContext, '/', '_')}"> 
+0

我正在使用substring-before($ contextPath,'/');這將拉第一次出現沒有/部分結果 –

+0

預期的輸出不包含斜槓。 –

+0

@lwburk:很對。我讀過XSLT的速度太快了。我想知道爲什麼你還沒有發佈這個答案,因爲在我來到這裏之前你一直在研究這個問題。現在我明白了! – LarsH

1

使用XSLT 2.0允許較短的,更容易和更有效的解決方案:

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

<xsl:variable name="vOutNames" select= 
    "tokenize(/*/*/output, '/')"/> 

<xsl:template match="/"> 
    <xsl:sequence select="my:gen($vOutNames)"/> 
</xsl:template> 

<xsl:function name="my:gen" as="element()?"> 
    <xsl:param name="pNames" as="xs:string*"/> 

    <xsl:if test="$pNames[1]"> 
    <xsl:element name="{$pNames[1]}"> 
    <xsl:sequence select="my:gen($pNames[position() >1])"/> 
    </xsl:element> 
    </xsl:if> 
</xsl:function> 
</xsl:stylesheet> 

當這個變換所提供的XML文檔施加:

<mappings> 
    <mapping inputContext="InputRoot" outputContext="outputRoot"> 
     <input>InputParent/InputChild/InputSubChild</input> 
     <output>OutputParent/OPChild</output> 
    </mapping> 
</mappings> 

想要的,正確的結果產生

<OutputParent> 
    <OPChild/> 
</OutputParent> 
+0

如果 InputParent/InputChild/InputSubChild OutputParent/OPChild

+0

@LaxmikanthSamudrala:對不起,你有什麼想說的? –

+0

對不起,這是我在處理其他XSLT問題上的錯誤;但我已經解決了這個問題。 –