2012-12-10 41 views
2

這是一個非常複雜的問題,超出了我對XSLT的知識 - 我仍在學習,無論我通過O'Reilly的XSLT書閱讀了多少內容,我都處於我的上方頭。XSLT - 重命名節點並刪除空格加更多

我有一個多問題的問題,我已經爲此生成了一個輸入XML文件,並且隨後也會嘗試解釋這些需求。

INPUT

<roottag> 
<body> 
    <header> 
     <r> 
      <c> 
       <d>Header Tag</d><!-- This can include spaces--> 
       <e>System generated trash</e> 
      </c> 
     </r> 
     <r> 
      <c> 
       <d>Sub Header Tag A</d> 
       <e>System generated trash</e> 
      </c> 
      <c> 
       <d>Sub Header Value A</d> 
       <e>System generated trash</e> 
      </c> 
     </r> 
     <r> 
      <c> 
       <d>Sub Header Tag B</d> 
       <e>System generated trash</e> 
      </c> 
      <c> 
       <d>Sub Header Value B</d> 
       <e>System generated trash</e> 
      </c> 
     </r> 
     <r> 
      <c> 
       <d>Sub Header Tag C</d> 
       <e>System generated trash</e> 
      </c> 
      <c> 
       <d>Sub Header Value C</d> 
       <e>System generated trash</e> 
      </c> 
     </r> 
    </header> 
    <information> 
     <r>Body of document</r> 
     <r>Appears here but have an XSLT that deals with this</r> 
    </informtaion> 
    <footer> 
     <r> 
      <c> 
       <d>Footer Tag</d><!-- This can include spaces--> 
       <e>System generated trash</e> 
      </c> 
     </r> 
     <r> 
      <c> 
       <d>Sub Footer Tag A</d> 
       <e>System generated trash</e> 
      </c> 
      <c> 
       <d>Sub Footer Value A</d> 
       <e>System generated trash</e> 
      </c> 
     </r> 
     <r> 
      <c> 
       <d>Sub Footer Tag B</d> 
       <e>System generated trash</e> 
      </c> 
      <c> 
       <d>Sub Footer Value B</d> 
       <e>System generated trash</e> 
      </c> 
     </r> 
     <r> 
      <c> 
       <d>Sub Footer Tag C</d> 
       <e>System generated trash</e> 
      </c> 
      <c> 
       <d>Sub Footer Value C</d> 
       <e>System generated trash</e> 
      </c> 
     </r> 
    </footer> 
</body> 
</roottag> 

輸出

<?xml version="1.0" encoding="utf-8"?> 
<roottag> 
    <body> 
    <header> 
     <HeaderTag> 
     <!-- without spaces --> 
     <HeaderName>Header Tag</HeaderName> 
     <!-- This needs to preserve spaces--> 
     </HeaderTag> 
     <SubHeaderTagA> 
     <!-- without spaces --> 
     <HeaderName>Sub Header Tag A</HeaderName> 
     <!-- This needs to preserve spaces--> 
     <HeaderValue>Sub Header Value A</HeaderValue> 
     </SubHeaderTagA> 
     <SubHeaderTagB> 
     <HeaderName>Sub Header Tag B</HeaderName> 
     <HeaderValue>Sub Header Value B</HeaderValue> 
     </SubHeaderTagB> 
     <SubHeaderTagC> 
     <HeaderName>Sub Header Tag C</HeaderName> 
     <HeaderValue>Sub Header Value C</HeaderValue> 
     </SubHeaderTagC> 
    </header> 
    <information> 
     <r>Body of document</r> 
     <r>Appears here but have an XSLT that deals with this</r> 
     </information> 
     <footer> 
     <FooterTag> 
      <FooterName>Footer Tag</FooterName> 
     </FooterTag> 
     <SubFooterTagA> 
      <FooterName>Sub Footer Tag A</FooterName> 
      <FooterValue>Sub Footer Value A</FooterValue> 
     </SubFooterTagA> 
     <SubFooterTagB> 
      <FooterName>Sub Footer Tag B</FooterName> 
      <FooterValue>Sub Footer Value B</FooterValue> 
     </SubFooterTagB> 
     <SubFooterTagC> 
      <FooterName>Sub Footer Tag C</FooterName> 
      <FooterValue>Sub Footer Value C</FooterValue> 
     </SubFooterTagC> 
     </footer> 
    </body> 
</roottag> 

這樣解釋,因爲我看到它的問題,我所面對的問題。

  1. RemovingSpaces: roottag /體/頭/ R/C/d內保存的值可以並且經常包含空格,所以我需要刪除此的一種方式,我已經從網站上的問題,發現[addLink]但是,這也會替換值,所以當我在後面的過程中使用數據時,它沒有輸出所需的空格。
  2. 用第一個值替換R: 我對如何做到這一點感到茫然,我試過並研究過的所有東西似乎都使用第二個值作爲值。我在我的結尾。
  3. 頁眉或頁腳名稱/值: 同樣,我的知識是有限的,如果這甚至是可能的,或者每個標籤需要單獨匹配?

  4. 運動的頁眉和頁腳標籤: 我沒有我需要的輸出中包含這一點,但我想我可能需要做的 - 這可能移動的標頭標記和頁腳標籤的外身體標籤?所以XML將是:roottag-header-body-information-/body-footer/-/rt

如果您需要更多的說明,請讓我知道。

+0

正在努力! +1好問題.. –

+0

我提供瞭解決方案!我們處理XML的想法可能會有所不同,但輸出將是相同的!首先使用我的XSLT代碼(在第8節中),看看你是否期待輸出!如果是,那麼通過解釋!我盡力讓它變得更簡單! –

回答

2

從源代碼中的元素內容而導出元素名稱通常是一個壞idea-雖然可以刪除空格,總會有其他特殊字符的可能性,即使你可能將它們全部刪除,你最終導致意外重複。例如,包含1 Tag2 Tag的兩個元素都需要分解爲Tag

然而,這樣的事情應該做的工作:

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

    <xsl:variable name="allowed">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvxyz_</xsl:variable> 

    <xsl:template match="r[c/d]"> 
    <xsl:variable name="elemName" select="translate(c/d,translate(c/d,$allowed,''),'')" /> 
    <xsl:element name="{$elemName}"> 
     <xsl:apply-templates /> 
    </xsl:element> 
    </xsl:template> 

    <xsl:template match="c"> 
    <xsl:apply-templates select="@* | node()"/> 
    </xsl:template> 

    <xsl:template match="c[1]/d"> 
    <HeaderName> 
     <xsl:apply-templates /> 
    </HeaderName> 
    </xsl:template> 

    <xsl:template match="c[2]/d"> 
    <HeaderValue> 
     <xsl:apply-templates /> 
    </HeaderValue> 
    </xsl:template> 

    <xsl:template match="e" /> 

    <xsl:template match="@* | node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

這裏使用了「雙轉換」的方法從字符串中去除所有不良分子。 translate函數可以用來從列表中刪除所有字符,方法是指定一個空字符串將這些字符轉換爲。您可以使用它從字符串中刪除所有VALID字符,只保留一個僅包含INVALID字符的字符串。然後您再次使用翻譯從原始字符串中刪除所有那些INVALID字符。

如果你需要你的頁眉/頁腳在身體之外,加入這些模板:

<xsl:template match="roottag"> 
    <xsl:copy> 
    <xsl:apply-templates select="body/header" /> 
    <xsl:apply-templates select="body" /> 
    <xsl:apply-templates select="body/footer" /> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="body"> 
    <xsl:copy> 
    <xsl:apply-templates select="information" /> 
    </xsl:copy> 
</xsl:template> 

要忽略r節點,其中c\d包含等號,加上這個模板下面的一個匹配「r[c/d]」:

<xsl:template match="r[contains(c/d,'=')]" /> 
+0

不錯! :)爲一個緊湊和完美的工作代碼+1! –

+0

@ flynn1179 - 非常感謝你。很乾淨,很容易理解。如果信息包含不需要的字符,我知道這些問題 - 我相信我可以在到達系統之前控制它,可能在提交「糟糕」輸入XML之前應用驗證腳本。 – 2eus

+0

如果包含某個值,是否有忽略帶有上述XSLT的節點(關於刪除空格/重命名)的方法? 例如有一個包含一個「=」標記。這裏沒有其他價值,可以刪除。 這是一個系統生成的值,不相信我可以刪除它 – 2eus

1

那麼有很多問題!所以多個答案..我會盡可能系統地寫,希望你能理解它!並隨時提問!

1.首先一步就是要標記之間擺脫額外的不利的空間。要實現這一目標有以下兩個語句作爲頭略低於XML聲明:

<xsl:output method="xml" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

2.Next一步定義身份temlpate!它的任務是輸出從輸入(除了什麼是不命令輸出)

<xsl:template match="@* | node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 

3.In你的輸出你不希望看到<r>元素!因此,我們將低於線

<xsl:template match="/roottag/body/header/r 
         |/roottag/body/footer/r"> 
    <xsl:apply-templates select="@*|node()"/> 
    </xsl:template> 

這不會複製<r>元素,但讓孩子元素拿過來!我將在下面寫..

4.You只想第一<c>標籤在每一個<r>複製元素..而忽略輸出<c>其餘節點..所以在下面定義模板覆蓋..

<xsl:template match="/roottag/body/header/r/c 
         |/roottag/body/footer/r/c"/> 

這實際上會從輸出中刪除所有<c>元素!但是下面的覆蓋將只處理第一個<c>元素!

5.此代碼是在輸出構建<Header>元!

<xsl:template match="/roottag/body/header/r/c[1]"> 
    <xsl:variable name="ElementName"> 
     <xsl:call-template name="RemoveSpaceFromValueD"> 
     <xsl:with-param name="text" select="d/."/> 
     <xsl:with-param name="replace" select="' '"/> 
     </xsl:call-template> 
    </xsl:variable> 

    <xsl:element name="{$ElementName}"> 
     <xsl:element name="HeaderName"> 
     <xsl:value-of select="d/."/> 
     </xsl:element> 
     <xsl:if test="ancestor::r != ancestor::header/r[1]"> 
     <xsl:element name="HeaderValue"> 
     <xsl:value-of select="e/."/> 
     </xsl:element> 
     </xsl:if> 
    </xsl:element> 
    </xsl:template> 

通過使用此代碼,您不必申報不同的模板對不同<header>, <footer> and <subHeaderTag>s

什麼,我在這裏做的是:

  1. 調用一個新的模板RemoveSpaceFromValueD將複製文本從元素d中刪除文本中的空格並將其分配給變量ElementName
  2. 使用從變量ElementName該值將被用於創建一個新元素!所以Sub Header Tag C將有<SubHeaderTagC>作爲父母:)
  3. <d>的值複製到<HeaderName>
  4. 從明年<c>複製下一個<d><HeaderValue>

6.重複相同的代碼<Footer>以及。

<xsl:template match="/roottag/body/footer/r/c[1]"> 
    <xsl:variable name="ElementName"> 
     <xsl:call-template name="RemoveSpaceFromValueD"> 
     <xsl:with-param name="text" select="d/."/> 
     <xsl:with-param name="replace" select="' '"/> 
     </xsl:call-template> 
    </xsl:variable> 

    <xsl:element name="{$ElementName}"> 
     <xsl:element name="FooterName"> 
     <xsl:value-of select="d/."/> 
     </xsl:element> 
     <xsl:if test="ancestor::r != ancestor::footer/r[1]"> 
     <xsl:element name="FooterValue"> 
      <xsl:value-of select="e/."/> 
     </xsl:element> 
     </xsl:if> 
    </xsl:element> 

    </xsl:template> 

7.And模板RemoveSpaceFromValueD

<xsl:template name="RemoveSpaceFromValueD"> 
    <xsl:param name="text"/> 
    <xsl:param name="replace"/> 
    <xsl:choose> 
     <xsl:when test="contains($text,$replace)"> 
     <xsl:value-of select="substring-before($text,$replace)"/> 
     <xsl:call-template name="RemoveSpaceFromValueD"> 
      <xsl:with-param name="text" select="substring-after($text,$replace)"/> 
      <xsl:with-param name="replace" select="$replace"/> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:value-of select="$text"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 

8.And整個XSLT代碼如下所示:

測試此!並讓我知道你是否有任何疑問或理解困難。

<?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:strip-space elements="*"/> 


    <xsl:template match="@* | node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@* | node()"/> 
    </xsl:copy> 
    </xsl:template> 


    <xsl:template match="/roottag/body/header/r 
         |/roottag/body/footer/r"> 
    <xsl:apply-templates select="@*|node()"/> 
    </xsl:template> 


    <xsl:template match="/roottag/body/header/r/c 
         |/roottag/body/footer/r/c"/> 


    <xsl:template match="/roottag/body/header/r/c[1]"> 
    <xsl:variable name="ElementName"> 
     <xsl:call-template name="RemoveSpaceFromValueD"> 
     <xsl:with-param name="text" select="d/."/> 
     <xsl:with-param name="replace" select="' '"/> 
     </xsl:call-template> 
    </xsl:variable> 

    <xsl:element name="{$ElementName}"> 
     <xsl:element name="HeaderName"> 
     <xsl:value-of select="d/."/> 
     </xsl:element> 
     <xsl:if test="ancestor::r != ancestor::header/r[1]"> 
     <xsl:for-each select="../c[2]"> 
      <xsl:element name="HeaderValue"> 
      <xsl:value-of select="d/."/> 
      </xsl:element> 
     </xsl:for-each> 
     </xsl:if> 
    </xsl:element> 

    </xsl:template> 


    <xsl:template match="/roottag/body/footer/r/c[1]"> 
    <xsl:variable name="ElementName"> 
     <xsl:call-template name="RemoveSpaceFromValueD"> 
     <xsl:with-param name="text" select="d/."/> 
     <xsl:with-param name="replace" select="' '"/> 
     </xsl:call-template> 
    </xsl:variable> 

    <xsl:element name="{$ElementName}"> 
     <xsl:element name="FooterName"> 
     <xsl:value-of select="d/."/> 
     </xsl:element> 
     <xsl:for-each select="../c[2]"> 
     <xsl:element name="FooterValue"> 
      <xsl:value-of select="d/."/> 
     </xsl:element> 
     </xsl:for-each> 
    </xsl:element> 

    </xsl:template> 


    <xsl:template name="RemoveSpaceFromValueD"> 
    <xsl:param name="text"/> 
    <xsl:param name="replace"/> 
    <xsl:choose> 
     <xsl:when test="contains($text,$replace)"> 
     <xsl:value-of select="substring-before($text,$replace)"/> 
     <xsl:call-template name="RemoveSpaceFromValueD"> 
      <xsl:with-param name="text" select="substring-after($text,$replace)"/> 
      <xsl:with-param name="replace" select="$replace"/> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:value-of select="$text"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 


</xsl:stylesheet> 
+0

非常感謝您的幫助 - 不需要知識,我們就能爲您提供詳細的信息和解釋。我在上面的XSLT中遇到了一個問題。使用此[在線工具之後(http://xslt.online-toolz.com/tools/xslt-transformation.php)它顯示的輸出中作爲 子標頭標記阿 系統產生的垃圾 2eus

+0

這應該閱讀 '子標題標籤的 子標頭值A ' – 2eus

+0

我已經編輯我的答案,請立即檢查! –