2012-04-11 51 views
2

使用Visual Studio在開發過程中執行轉換時,生成的xml包含目標中的源xml文本,該文本包含在與我的模板條件不匹配的標記中XSLT(XML to XML)輸出包含源不匹配的數據

我期待我的選擇集團在第一個模板找到名爲組,是CrystalReport直接孩子的任何元素,並通過他們在應用模板調用。我知道我的第二個模板上的匹配過濾器只會在的屬性爲Level = 1並將其寫出。我期望一切被忽略。

爲什麼「not this」出現在我的輸出中?

<?xml version="1.0" encoding="utf-8" ?> 
<!-- 
UPDATE: Note that adding the xmlns attribute causes all output 
to disappear unless you use Chris's second solution. 
--> 
<CrystalReport xmlns="urn:crystal-reports:schemas:report-detail" > 
    <Group Level="1"> 
    <GroupHeader> 
     <Section> 
     <Field FieldName="apple" /> 
     </Section> 
    </GroupHeader> 
    <Group Level="2"> 
     not this 
    </Group> 
    </Group> 
</CrystalReport> 

變換

<?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="/CrystalReport"> 
    <root> 
     <xsl:apply-templates select="Group"/> 
    </root> 
    </xsl:template> 

    <xsl:template match="Group[@Level='1']/GroupHeader"> 
    <tag1><xsl:value-of select="Section/Field/@FieldName"/></tag1> 
    </xsl:template> 
</xsl:stylesheet> 

輸出

<?xml version="1.0" encoding="utf-8"?> 
<root> 
    <tag1>apple</tag1> 
     not this 
    </root> 

回答

2

你正面臨在內置XML解析器的模板開始發揮作用的問題。您將模板應用於所有Group元素,但只能使用自己的模板捕捉其中一個模板。另一個由輸出所有節點值的默認模板處理。我建議你改變

<xsl:template match="/CrystalReport"> 

<xsl:template match="/"> 

這將覆蓋其產生額外的輸出根默認模板。您可以在http://www.w3.org/TR/xslt#built-in-rule

找到更多的內置模板規則然後覆蓋基本的文本()模板,所以你最終XSLT看起來有點像這樣

<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="/"> 
    <root> 
     <xsl:apply-templates select="CrystalReport/Group"/> 
    </root> 
</xsl:template> 
<xsl:template match="Group[@Level='1']/GroupHeader"> 
    <tag1> 
     <xsl:value-of select="Section/Field/@FieldName"/> 
    </tag1> 
</xsl:template> 
<xsl:template match="text()"/> 

UPDATE

或者更簡單,你可以匹配所需的元素,並使用類似這樣的東西

<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="/CrystalReport"> 
    <root> 
     <xsl:apply-templates select="Group[@Level='1']/GroupHeader"/> 
    </root> 
</xsl:template> 
<xsl:template match="GroupHeader"> 
    <tag1> 
     <xsl:value-of select="Section/Field/@FieldName"/> 
    </tag1> 
</xsl:template> 

這將保留默認的文本()模板,這可以非常方便。

+0

謝謝,並獲得成功,我曾讀過關於空模板)匹配的文本(但必須用我的基本模板 – 2012-04-11 10:46:22

+0

無根的比賽一直很高興幫助,您的評論促使我使用更多原始代碼添加一個稍微更乾淨的示例。 – 2012-04-11 10:53:53

+0

我的示例是真正問題的簡化示例,現在我發現將名稱空間添加回CrystalReport元素會導致不返回數據(xmlns =「urn:crystal-reports:schemas:report-detail」) ,我相信我已經看到了名稱空間解決方案,我會看看。感謝您的更新,我也會嘗試。 – 2012-04-11 11:23:08

0

嘗試

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:crystal="urn:crystal-reports:schemas:report-detail"> 
<xsl:output method="xml" indent="yes"/> 
<xsl:strip-space elements="*"/> 
<xsl:template match="/crystal:CrystalReport"> 
    <root> 
     <xsl:apply-templates select="crystal:Group[@Level='1']/crystal:GroupHeader"/> 
    </root> 
</xsl:template> 
<xsl:template match="crystal:GroupHeader"> 
    <tag1> 
     <xsl:value-of select="crystal:Section/crystal:Field/@FieldName"/> 
    </tag1> 
</xsl:template> 

+0

唯一的變化是命名空間聲明(現在已在原始問題中更新),沒有在xml主體中的元素上定義名稱空間 – 2012-04-11 11:36:27

+0

這非常奇怪,我只是在更新後的XML上嘗試了我的XSLT,並提供了所需的輸出。您確定您複製了整個XSLT,特別是頂部的xmlns:crystal =「urn:crystal-reports:schemas:report-detail」參考嗎? – 2012-04-11 11:48:23

+0

啊,我沒有意識到命名空間機制。我解釋你的答案意味着我的源代碼中有名稱空間前綴的xml元素名稱(在我的防守中,重要的一點是滾動代碼塊),在那裏你真的知道你在說什麼;-)和我在另一方面不要 – 2012-04-11 11:55:45