2011-04-21 80 views
4

我寫XSLT文件用下面的代碼:如何避免在XSLT中生成空屬性?

<xsl:attribute name="subCode"> 
    <xsl:value-of select="Field[@key='XY']"/> 
</xsl:attribute> 

比方說,我的輸入XML看起來是這樣的:

[...] 
<Field key="XY"/> 
[...] 

在這種情況下我的XSLT會生成以下的輸出:

<SomeElement subCode=""> 
[...] 
</SomeElement> 

我的問題是:如何刪除空屬性subCode=""?我知道使用<xsl:if>這樣的條件指令是可能的,但是,這似乎是一個醜陋的解決方案(因爲我在XSLT中生成了數以千計的類似屬性)。

它必須在同一個XSLT中完成。我無法在其他XSLT文件中添加後期處理。

除此之外,輸出XML已定義了其XSD架構。架構說這個屬性是可選。也許有一種方法可以將XSD模式應用於輸出XML?

在此先感謝您的幫助!

+0

好問題,+1。查看我的答案,獲得所有答案中最短,最精確的完整解決方案。 – 2011-04-21 12:52:13

回答

4

使用

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

<xsl:template match="/*"> 
    <someElement> 
    <xsl:apply-templates mode="attr"/> 
    </someElement> 
</xsl:template> 

<xsl:template match="Field[@key='XY' and not(.='')]" mode="attr"> 
    <xsl:attribute name="subCode"> 
     <xsl:value-of select="."/> 
    </xsl:attribute> 
</xsl:template> 
</xsl:stylesheet> 

當該變換被應用在下面的XML文檔:

<t> 
<Field key="XY"/> 
</t> 

有用,正確的結果(產生根本沒有屬性)產生

當源XML文檔是這樣的:

<t> 
<Field key="XY">1</Field> 
</t> 

相同transforma再次產生正確的,想要的結果;

<someElement subCode="1"/> 
+0

+1這是正確的:測試元素的字符串值。其他謂詞是'[string()]'和'[normalize-space()]'。 – 2011-04-21 15:22:28

+1

@Alejandro你提出的兩個謂詞都會返回'false()'爲字符串'「0」' – 2011-04-21 15:46:40

+0

+1 from me for the correct solution – andyb 2011-04-21 16:13:54

0

您應該應用以下模板到你的屬性:

<xsl:template match="@key['XY']"> 
    <xsl:attribute name="subCode"> 
     <xsl:value-of select="."/> 
    </xsl:attribute> 
</xsl:template> 

此模板上的所有關鍵屬性相匹配:

這個模板是誰的所有關鍵的屬性值是「XY」匹配(文本)值大於0:

<xsl:template match="@key[string-length(.)]"> 
    <xsl:attribute name="other"> 
     <xsl:value-of select="."/> 
    </xsl:attribute> 
</xsl:template> 

最後t他的模板匹配所有是空的屬性(*):

<xsl:template match="@*[not(string-length(.))]" /> 

所以,如果你有一個像

<?xml version="1.0"?> 
<Root> 
    <Field key='v'>One</Field> 
    <Field key='XY'>Two</Field> 
    <Field key='a'>Three</Field> 
    <Field key='v'>Four</Field> 
    <Field key='XY'>Five</Field> 
    <Field>Six</Field> 
    <Field>Seven</Field> 
    <Field key='b'>Eight</Field> 
    <Field key=''>Nine</Field> 
    <Field></Field> 
    <Field key='x'>Eleven</Field> 
    <Field key=''>Twelve</Field> 
    <Field lat='x'>Thirteen</Field> 
</Root> 

可以產生輸出輸入:使用

<?xml version='1.0' ?> 
<Root> 
    <SomeField other="v">One</SomeField> 
    <SomeField subCode="XY">Two</SomeField> 
    <SomeField other="a">Three</SomeField> 
    <SomeField other="v">Four</SomeField> 
    <SomeField subCode="XY">Five</SomeField> 
    <SomeField>Six</SomeField> 
    <SomeField>Seven</SomeField> 
    <SomeField other="b">Eight</SomeField> 
    <SomeField>Nine</SomeField> 
    <SomeField/> 
    <SomeField other="x">Eleven</SomeField> 
    <SomeField>Twelve</SomeField> 
    <SomeField>xThirteen</SomeField> 
</Root> 

以下xslt:

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

    <xsl:template match="/"> 
     <Root> 
      <xsl:apply-templates/> 
     </Root> 
    </xsl:template> 

    <xsl:template match="Field"> 
     <xsl:element name="SomeField"> 
      <xsl:apply-templates select="@*"/> 
      <xsl:value-of select="text()"/> 
     </xsl:element> 
    </xsl:template> 

    <xsl:template match="@key['XY']"> 
     <xsl:attribute name="subCode"> 
      <xsl:value-of select="."/> 
     </xsl:attribute> 
    </xsl:template> 

    <xsl:template match="@key[string-length(.)]"> 
     <xsl:attribute name="other"> 
      <xsl:value-of select="."/> 
     </xsl:attribute> 
    </xsl:template> 

    <xsl:template match="@key[not(string-length(.))]" /> 
</xsl:stylesheet> 
+0

謝謝,你在答案中付出了很多努力。但是,我覺得我沒有明確表達我想達到的目標。我想要的是簡單地跳過生成空屬性。 – Lukasz 2011-04-21 12:56:06

1

You ca n定義一個模板以匹配屬性,該屬性將爲您提供缺失的@key的正確輸出,但是如果還添加了謂詞[.!=''],則它應該忽略沒有值的屬性。

<xsl:template match="@key[.!='']"> 
    <xsl:attribute name="subCode"><xsl:value-of select="."/></xsl:attribute> 
</xsl:template> 

或者在你的例子,如果你只希望@key='XY'匹配使用:

<xsl:template match="@key[.='XY']"> 
    <xsl:attribute name="subCode"><xsl:value-of select="."/></xsl:attribute> 
</xsl:template> 

編輯:這裏是我用來測試這是一個更完整的例子。

源XML

<Fields> 
    <Field key="XY">A</Field> 
    <Field key="XY">B</Field> 
    <Field key="">C</Field> 
    <Field>D</Field> 
</Fields> 

伴隨XSL

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

<xsl:template match="/"> 
    <output> 
    <xsl:apply-templates /> 
    </output> 
</xsl:template> 

<xsl:template match="Field"> 
    <xsl:element name="NewField"> 
    <xsl:apply-templates select="@*"/> 
    <xsl:value-of select="."/> 
    </xsl:element> 
</xsl:template> 

<xsl:template match="@key[.='XY']"> 
    <xsl:attribute name="subCode"><xsl:value-of select="."/></xsl:attribute> 
</xsl:template> 
</xsl:stylesheet> 

結果

<output> 
    <NewField subCode="XY">A</NewField> 
    <NewField subCode="XY">B</NewField> 
    <NewField>C</NewField> 
    <NewField>D</NewField> 
</output> 
+0

我不認爲OP是要求屬性的字符串值,但元素的字符串值。 – 2011-04-21 15:23:34

+0

啊,是的,我誤解了一下這個問題! – andyb 2011-04-21 16:13:27