2016-08-08 75 views
0

我新引入xslt,我正在做一些小任務來熟悉xslt。但我陷入了一個問題,我無法解決將xml文件轉換爲另一個問題。 場景: 輸入是一個xml文件,包含節點,每一個都是一對子和父標記,它們通過標記指示當前節點的名稱,父節點的名稱由標記< father>。 我想要做的是生成一個節點樹,第一個節點是沒有父親的節點(我在樹1中手動創建了名稱爲0和級別的節點),然後查找具有父標籤的所有節點(0)作爲第一步,我會得到我的輸入文件(1和4),在這裏我創建一個新的節點到節點(0)持有名稱(1),並在樹中有一個級別等於( 2)然後我會去查找父標籤等於(1)等的所有節點,當我到達沒有更多孩子的地方(1)時,我將創建另一個名爲(4)的節點)並且與名稱爲(1)的節點在樹中具有相同的級別,然後繼續查找父標籤等於(4)等等的節點。 我有這樣的XML:遞歸和TreeNode xslt

<TypedPolling xmlns="http://schemas.microsoft.com/Sql/2008/05/TypedPolling"> 
    <TypedPolling0> 
     <TypedPolling0> 
      <son>1</son> 
      <father>0</father> 
     </TypedPolling0> 
     <TypedPolling0> 
      <son>2</son> 
      <father>1</father> 
     </TypedPolling0> 
     <TypedPolling0> 
      <son>3</son> 
      <father>0</father> 
     </TypedPolling0> 
     <TypedPolling0> 
      <son>4</son> 
      <father>3</father> 
     </TypedPolling0> 
    </TypedPolling0> 
</TypedPolling> 

以前的xml文件應該被改造成該XML文件:

<ns0:TreeNode> 
    <ns0:node>0</ns0:node> 
    <ns0:LevelInTree>1</ns0:LevelInTree> 
    <ns0:TreeNode> 
     <ns0:node>1</ns0:node> 
     <ns0:LevelInTree>2</ns0:LevelInTree> 
     <ns0:TreeNode> 
     <ns0:node>2</ns0:node> 
     <ns0:LevelInTree>3</ns0:LevelInTree> 
     </ns0:TreeNode> 
    </ns0:TreeNode> 
    <ns0:TreeNode> 
     <ns0:node>3</ns0:node> 
     <ns0:LevelInTree>2</ns0:LevelInTree> 
     <TreeNode> 
      <ns0:node>4</ns0:node> 
      <ns0:LevelInTree>3</ns0:LevelInTree> 
     </TreeNode> 
    </TreeNode> 
</TreeNode> 

我寫來轉換輸入的代碼是(我用的關鍵要素,以獲得誰擁有指定的父親名字的兒子):

<?xml version="1.0" encoding="UTF-16"?> 
<xsl:stylesheet version="1.0" 
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
      xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" 
      xmlns:s0="http://schemas.microsoft.com/Sql/2008/05/TypedPolling" 
      xmlns:ns0="http://NO.Aditro.Schemas.Organization.OrganizationTrees" 
      xmlns:userCSharp="http://schemas.microsoft.com/BizTalk/2003/userCSharp" 
      exclude-result-prefixes="msxsl var s0 userCSharp"> 
<xsl:output omit-xml-declaration="yes" method="xml" indent="yes" version="1.0" /> 
<xsl:key name="KeyItemFather" match="/s0:TypedPolling/s0:TypedPolling0/s0:TypedPolling0" use="@father" /> 

<xsl:template match="/"> 
    <xsl:variable name="son" select="0" /> 
    <xsl:variable name="level" select="1" /> 
    <xsl:apply-templates mode="NewNode" select="/s0:TypedPolling/s0:TypedPolling0"> 
     <xsl:with-param name="level" select="$level" /> 
    </xsl:apply-templates> 
</xsl:template> 

<xsl:template name="NewTreeNode" match="/s0:TypedPolling/s0:TypedPolling0/s0:TypedPolling0" mode="NewNode"> 
<xsl:param name="son" /> 
<xsl:param name="level" /> 
    <ns0:TreeNode> 
     <ns0:node> 
     <xsl:value-of select="$son" /> 
     </ns0:node> 
     <ns0:LevelInTree> 
     <xsl:value-of select="$level" /> 
     </ns0:LevelInTree> 
     <xsl:apply-templates select="key('KeyItemFather', $son)" mode="NewNode"> 
     <xsl:with-param name="level" select="$level+1" /> 
     </xsl:apply-templates> 
    </ns0:TreeNode> 
</xsl:template> 
</xsl:stylesheet> 

我的問題是遞歸一些錯誤期間發生的遞歸不斷去無休止地和<ns0:node></ns0:node>保留爲空(它應該是例如<ns0:node>3</ns0:node>)。我找不到我的錯誤在哪裏! :(

+0

歡迎SO!請[編輯]您的問題,並添加關於您正在使用的*精確*問題的信息 - 您是否收到錯誤消息?如果是,什麼錯誤信息?你得到的輸出是否與預期的輸出不同?如果是,如何? –

+0

請解釋所需轉換的邏輯。 - 還要注意你給我們的輸出有一個未定義的前綴。 –

+0

@ michael.hor257k根據我從你的問題中瞭解到的情況,我所做的轉換全部都是將一個xml文件轉換成節點樹,其中節點包含節點< father >並且每個節點都有一個級別表示它有多遠來自第一個節點。請糾正我,如果我不正確地得到你的問題! –

回答

0
<?xml version="1.0" encoding="utf-16"?> 
<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
       xmlns:var="http://schemas.microsoft.com/BizTalk/2003/var" 
       xmlns:s0="http://schemas.microsoft.com/Sql/2008/05/TypedPolling" 
       xmlns:ns0="http://NO.Aditro.Schemas.Organization.OrganizationTrees" 
       exclude-result-prefixes="msxsl var s0"> 

    <xsl:output omit-xml-declaration="yes" method="xml" indent="yes" version="1.0" /> 
    <xsl:template match="/"> 
     <xsl:variable name="FirstNodeSon" select="0" /> 
     <xsl:variable name="FirstNodelevel" select="1" /> 
     <ns0:TreeNode> 
      <ns0:node> 
      <xsl:value-of select="$FirstNodeSon"/> 
      </ns0:node> 
      <ns0:LevelInTree> 
      <xsl:value-of select="$FirstNodelevel"/> 
      </ns0:LevelInTree> 
      <xsl:apply-templates mode="NewNode" select="s0:TypedPolling/s0:TypedPolling0/s0:TypedPolling0[s0:father=$FirstNodeSon]"> 
      <xsl:with-param name="level" select="$FirstNodelevel+1" /> 
      </xsl:apply-templates> 
     </ns0:TreeNode> 
    </xsl:template> 
    <xsl:template name="NewTreeNode" match="s0:TypedPolling0" mode="NewNode"> 
    <xsl:param name="level" /> 
    <xsl:variable name="CurrentNodeSon" select="s0:Son" /> 
    <ns0:TreeNode> 
     <ns0:node> 
     <xsl:value-of select="s0:Son" /> 
     </ns0:node> 
     <ns0:LevelInTree> 
     <xsl:value-of select="$level" /> 
     </ns0:LevelInTree> 
     <xsl:apply-templates select="/s0:TypedPolling/s0:TypedPolling0/s0:TypedPolling0[s0:father=$CurrentNodeSon]" mode="NewNode"> 
     <xsl:with-param name="level" select="$level+1" /> 
     </xsl:apply-templates> 
    </ns0:TreeNode> 
    </xsl:template> 
</xsl:stylesheet> 
+0

你對'mode'的使用是不必要的和令人困惑的。 OTOH,你*應該*使用'key'來獲取子節點 - 就像你在OP中開始的一樣。 - P.S.我相信如果你解決了這個問題並刪除所有冗餘變量和名稱空間聲明,你將會得到我發佈的答案。 –

0

它在我看來好像你非常接近:設計方法當然是正確的,在你沒有向我們展示的東西中可能存在錯誤,比如命名空間聲明 - 顯示完整的可運行樣式表,所以我們可以自己嘗試,並使用我們最喜歡的調試工具,而不必填寫你遺漏的位。

我發現令人困惑的事情是,你的源數據以一個TypedPolling開始標記開頭,隨後是三個TypedPolling0開始標籤,前兩個開始標籤沒有相應的結束標籤,假設你剛剛把這些標籤留下了,你的father元素有四個深度,所以你的xsl:key聲明有兩個錯誤:首先它匹配father屬性而不是元素(use="@father"),其次它的祖先級別太少。請注意,你實際上並不需要在這裏指定一個完整路徑,這將是非常不夠的說

<xsl:key name="KeyItemFather" match="s0:TypedPolling0" use="father" /> 

我注意到的另一件事是,你的模板規則有兩個參數,但(在兩個呼叫)你是隻提供一個。實際上,您不需要參數$son,因爲您可以通過從上下文節點訪問child::son來獲取該信息。

+0

親愛Mr.Kay, 我已經添加了命名空間和編輯的源代碼,希望它成爲更容易被測試...謝謝 –

+0

OK,這意味着'的xsl:鍵/ @ match'現在是正確的,但是' @ use'仍然是錯的,而且還是你與兩個參數聲明模板,並只與一個稱之爲問題。 –

0

AFAICT,你想要做這樣的事情:

XSLT 1。0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:s0="http://schemas.microsoft.com/Sql/2008/05/TypedPolling" 
xmlns:ns0="http://NO.Aditro.Schemas.Organization.OrganizationTrees" 
exclude-result-prefixes="s0"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:key name="children" match="s0:TypedPolling0" use="s0:father" /> 

<xsl:template match="/"> 
    <!-- create root node --> 
    <ns0:TreeNode> 
     <ns0:node>0</ns0:node> 
     <ns0:LevelInTree>1</ns0:LevelInTree> 
     <!-- get top-level nodes --> 
     <xsl:apply-templates select="key('children', 0)"> 
      <xsl:with-param name="level" select="2" /> 
     </xsl:apply-templates> 
    </ns0:TreeNode> 
</xsl:template> 

<xsl:template match="s0:TypedPolling0"> 
    <xsl:param name="level"/> 
    <ns0:TreeNode> 
     <ns0:node> 
      <xsl:value-of select="s0:son" /> 
     </ns0:node> 
     <ns0:LevelInTree> 
      <xsl:value-of select="$level" /> 
     </ns0:LevelInTree> 
     <!-- get children --> 
     <xsl:apply-templates select="key('children', s0:son)"> 
      <xsl:with-param name="level" select="$level + 1" /> 
     </xsl:apply-templates> 
    </ns0:TreeNode> 
</xsl:template> 

</xsl:stylesheet> 

當適用於您的輸入樣本,結果將是:

<?xml version="1.0" encoding="UTF-8"?> 
<ns0:TreeNode xmlns:ns0="http://NO.Aditro.Schemas.Organization.OrganizationTrees"> 
    <ns0:node>0</ns0:node> 
    <ns0:LevelInTree>1</ns0:LevelInTree> 
    <ns0:TreeNode> 
     <ns0:node>1</ns0:node> 
     <ns0:LevelInTree>2</ns0:LevelInTree> 
     <ns0:TreeNode> 
     <ns0:node>2</ns0:node> 
     <ns0:LevelInTree>3</ns0:LevelInTree> 
     </ns0:TreeNode> 
    </ns0:TreeNode> 
    <ns0:TreeNode> 
     <ns0:node>3</ns0:node> 
     <ns0:LevelInTree>2</ns0:LevelInTree> 
     <ns0:TreeNode> 
     <ns0:node>4</ns0:node> 
     <ns0:LevelInTree>3</ns0:LevelInTree> 
     </ns0:TreeNode> 
    </ns0:TreeNode> 
</ns0:TreeNode>