2011-09-19 40 views
2

我對XSL相對來說比較新,並且試圖將Google日曆提要優雅地轉換爲更具可讀性的內容。XSLT的優化

我會感激你的眼睛是否有優化。特別是,我希望您對模板使用的建議。我已經閱讀了很多關於for-each不適合使用無用的(而是應該嘗試對模板進行審慎使用的)。

非常感謝。

原始XML(僅示出一個事件):

<?xml version='1.0' encoding='UTF-8'?> 
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gCal='http://schemas.google.com/gCal/2005' xmlns:gd='http://schemas.google.com/g/2005'> 
    <id>http://www.google.com/calendar/feeds/bachya1208%40gmail.com/public/full</id> 
    <updated>2011-09-19T21:32:50.000Z</updated> 
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'/> 
    <title type='text'>John Doe</title> 
    <subtitle type='text'>John Doe</subtitle> 
    <link rel='alternate' type='text/html' href='https://www.google.com/calendar/[email protected]'/> 
    <link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full'/> 
    <link rel='http://schemas.google.com/g/2005#batch' type='application/atom+xml' href='https://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full/batch'/> 
    <link rel='self' type='application/atom+xml' href='https://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full?max-results=25'/> 
    <link rel='next' type='application/atom+xml' href='https://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full?start-index=26&amp;max-results=25'/> 
    <author> 
     <name>John Doe</name> 
     <email>[email protected]</email> 
    </author> 
    <generator version='1.0' uri='http://www.google.com/calendar'>Google Calendar</generator> 
    <openSearch:totalResults>1334</openSearch:totalResults> 
    <openSearch:startIndex>1</openSearch:startIndex> 
    <openSearch:itemsPerPage>25</openSearch:itemsPerPage> 
    <gCal:timezone value='America/Denver'/> 
    <gCal:timesCleaned value='0'/> 
    <entry> 
     <id>http://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full/lp0upnpndnkp0ruqht7ef84kds</id> 
     <published>2011-09-14T21:15:16.000Z</published> 
     <updated>2011-09-14T21:15:16.000Z</updated> 
     <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'/> 
     <title type='text'>Oil Change</title> 
     <content type='text'/> 
     <link rel='alternate' type='text/html' href='https://www.google.com/calendar/event?eid=bHAwdXBucG5kbmtwMHJ1cWh0N2VmODRrZHMgYmFjaHlhMTIwOEBt' title='alternate'/> 
     <link rel='self' type='application/atom+xml' href='https://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full/lp0upnpndnkp0ruqht7ef84kds'/> 
     <author> 
      <name>John Doe</name> 
      <email>[email protected]</email> 
     </author> 
     <gd:comments> 
      <gd:feedLink href='https://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full/lp0upnpndnkp0ruqht7ef84kds/comments'/> 
     </gd:comments> 
     <gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'/> 
     <gd:where valueString='9955 E Arapahoe Road, Englewood, CO 80112 (Go Subaru Arapahoe)'/> 
     <gd:who email='[email protected]' rel='http://schemas.google.com/g/2005#event.organizer' valueString='[email protected]'/> 
     <gd:when endTime='2011-09-29T11:30:00.000-06:00' startTime='2011-09-29T10:30:00.000-06:00'/> 
     <gd:transparency value='http://schemas.google.com/g/2005#event.opaque'/> 
     <gCal:anyoneCanAddSelf value='false'/> 
     <gCal:guestsCanInviteOthers value='true'/> 
     <gCal:guestsCanModify value='false'/> 
     <gCal:guestsCanSeeGuests value='true'/> 
     <gCal:sequence value='0'/> 
     <gCal:uid value='[email protected]'/> 
    </entry> 
</feed> 

XSLT:

<?xml version="1.0"?> 
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 
    <xsl:template name="formatDateTime"> 
     <xsl:param name="dateTime" /> 
     <xsl:value-of select="concat(substring-before($dateTime, 'T'), ' ', substring-before(substring-after($dateTime, 'T'), '.'))" /> 
    </xsl:template> 
    <xsl:template match="/"> 
     <Events> 
      <xsl:apply-templates select="/*/*[local-name()= 'entry']" /> 
     </Events> 
    </xsl:template> 
    <xsl:template match="*[local-name()= 'entry']"> 
     <xsl:variable name="startDateTime" select="*[name() = 'gd:when']/@*[local-name() = 'startTime']" /> 
     <xsl:variable name="endDateTime" select="*[name() = 'gd:when']/@*[local-name() = 'endTime']" /> 
     <Event> 
      <EventTitle> 
       <xsl:value-of select="*[local-name() = 'title'][1]" /> 
      </EventTitle> 
      <StartDateTime> 
       <xsl:call-template name="formatDateTime"> 
        <xsl:with-param name="dateTime" select="$startDateTime" /> 
       </xsl:call-template> 
      </StartDateTime> 
      <EndDateTime> 
       <xsl:call-template name="formatDateTime"> 
        <xsl:with-param name="dateTime" select="$endDateTime" /> 
       </xsl:call-template> 
      </EndDateTime> 
      <Who> 
       <xsl:value-of select="*[local-name() = 'author']/*[local-name() = 'name']" /> 
      </Who> 
      <Where> 
       <xsl:value-of select="*[name() = 'gd:where']/@*[local-name() = 'valueString']" /> 
      </Where> 
      <Status> 
       <xsl:value-of select="*[name() = 'gd:eventStatus']/@*[local-name() = 'value']" /> 
      </Status> 
     </Event> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

<?xml version="1.0" encoding="UTF-16"?> 
<Events> 
    <Event> 
     <EventTitle>Oil Change</EventTitle> 
     <StartDateTime>2011-09-29 10:30:00</StartDateTime> 
     <EndDateTime>2011-09-29 11:30:00</EndDateTime> 
     <Who>John Doe</Who> 
     <Where>9955 E Arapahoe Road, Englewood, CO 80112 (Go Subaru Arapahoe)</Where> 
     <Status>http://schemas.google.com/g/2005#event.confirmed</Status> 
    </Event> 
</Events> 
+0

爲什麼'local-name'常常被用來代替名稱空間? – Jacob

+0

只有無知 - 由於某種原因,我永遠無法使用樣式表工作而不使用local name()'... – ABach

回答

2

ÿ我們的方法對我來說很好。我認爲你的XPath代碼會更乾淨,如果你使用常規元素選擇而不是local-name,那麼運行速度可能會更快。您可能與您的XPath掙扎的原因是因爲您正在使用默認名稱空間爲http://www.w3.org/2005/Atom的XML,並且該名稱空間未在您的樣式表中聲明。這裏有一個更簡單的樣式表可以怎樣看一個片斷,使用f:前綴爲飼料命名空間:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:f="http://www.w3.org/2005/Atom" 
       xmlns:gd="http://schemas.google.com/g/2005"> 

    <!-- ... --> 

    <xsl:template match="/"> 
    <Events> 
     <xsl:apply-templates select="//f:entry" /> 
    </Events> 
    </xsl:template> 

    <xsl:template match="f:entry"> 
    <xsl:variable name="startDateTime" select="gd:when/@startTime" /> 
    <xsl:variable name="endDateTime" select="gd:when/@endTime" /> 
    <Event> 
     <EventTitle> 
      <xsl:value-of select="f:title[1]" /> 
     </EventTitle> 
     <StartDateTime> 
      <xsl:call-template name="formatDateTime"> 
       <xsl:with-param name="dateTime" select="$startDateTime" /> 
      </xsl:call-template> 
     </StartDateTime> 
     <EndDateTime> 
      <xsl:call-template name="formatDateTime"> 
       <xsl:with-param name="dateTime" select="$endDateTime" /> 
      </xsl:call-template> 
     </EndDateTime> 
     <Who> 
      <xsl:value-of select="f:author/f:name" /> 
     </Who> 
     <Where> 
      <xsl:value-of select="gd:where/@valueString" /> 
     </Where> 
     <Status> 
      <xsl:value-of select="gd:eventStatus/@value" /> 
     </Status> 
    </Event> 
    </xsl:template> 

    <!-- etc --> 

</xsl:stylesheet> 
+0

這可能是任何人向我解釋XML命名空間時最清楚的。謝謝! – ABach

1

這是一個完整的轉型是從所提供的衍生,解決了默認命名空間問題(如已通過@Jacob完成),而且還完全消除了輸出端上的不必要的模板匹配文檔節點(/)和確保兩個不需要的命名空間將不會出現在每一個(文字結果)元件:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:a="http://www.w3.org/2005/Atom" 
    xmlns:gd="http://schemas.google.com/g/2005" 
    exclude-result-prefixes="a gd"> 

    <xsl:output omit-xml-declaration="yes" indent="yes"/> 

    <xsl:template match="a:entry[1]"> 
    <Events> 
     <xsl:apply-templates select="../a:entry" mode="process"/> 
    </Events> 
    </xsl:template> 

    <xsl:template match="a:entry" mode="process"> 
    <xsl:variable name="startDateTime" select="gd:when/@startTime" /> 
    <xsl:variable name="endDateTime" select="gd:when/@endTime" /> 
    <Event> 
     <EventTitle> 
      <xsl:value-of select="a:title[1]" /> 
     </EventTitle> 
     <StartDateTime> 
      <xsl:call-template name="formatDateTime"> 
       <xsl:with-param name="dateTime" select="$startDateTime" /> 
      </xsl:call-template> 
     </StartDateTime> 
     <EndDateTime> 
      <xsl:call-template name="formatDateTime"> 
       <xsl:with-param name="dateTime" select="$endDateTime" /> 
      </xsl:call-template> 
     </EndDateTime> 
     <Who> 
      <xsl:value-of select="a:author/a:name" /> 
     </Who> 
     <Where> 
      <xsl:value-of select="gd:where/@valueString" /> 
     </Where> 
     <Status> 
      <xsl:value-of select="gd:eventStatus/@value" /> 
     </Status> 
    </Event> 
    </xsl:template> 

    <xsl:template name="formatDateTime"> 
     <xsl:param name="dateTime" /> 
     <xsl:value-of select="concat(substring-before($dateTime, 'T'), ' ', substring-before(substring-after($dateTime, 'T'), '.'))" /> 
    </xsl:template> 

<xsl:template match="text()|a:entry"/> 
</xsl:stylesheet> 

當這種轉化應用所提供的XML文檔

<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gCal='http://schemas.google.com/gCal/2005' xmlns:gd='http://schemas.google.com/g/2005'> 
    <id>http://www.google.com/calendar/feeds/bachya1208%40gmail.com/public/full</id> 
    <updated>2011-09-19T21:32:50.000Z</updated> 
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'/> 
    <title type='text'>John Doe</title> 
    <subtitle type='text'>John Doe</subtitle> 
    <link rel='alternate' type='text/html' href='https://www.google.com/calendar/[email protected]'/> 
    <link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full'/> 
    <link rel='http://schemas.google.com/g/2005#batch' type='application/atom+xml' href='https://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full/batch'/> 
    <link rel='self' type='application/atom+xml' href='https://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full?max-results=25'/> 
    <link rel='next' type='application/atom+xml' href='https://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full?start-index=26&amp;max-results=25'/> 
    <author> 
     <name>John Doe</name> 
     <email>[email protected]</email> 
    </author> 
    <generator version='1.0' uri='http://www.google.com/calendar'>Google Calendar</generator> 
    <openSearch:totalResults>1334</openSearch:totalResults> 
    <openSearch:startIndex>1</openSearch:startIndex> 
    <openSearch:itemsPerPage>25</openSearch:itemsPerPage> 
    <gCal:timezone value='America/Denver'/> 
    <gCal:timesCleaned value='0'/> 
    <entry> 
     <id>http://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full/lp0upnpndnkp0ruqht7ef84kds</id> 
     <published>2011-09-14T21:15:16.000Z</published> 
     <updated>2011-09-14T21:15:16.000Z</updated> 
     <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'/> 
     <title type='text'>Oil Change</title> 
     <content type='text'/> 
     <link rel='alternate' type='text/html' href='https://www.google.com/calendar/event?eid=bHAwdXBucG5kbmtwMHJ1cWh0N2VmODRrZHMgYmFjaHlhMTIwOEBt' title='alternate'/> 
     <link rel='self' type='application/atom+xml' href='https://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full/lp0upnpndnkp0ruqht7ef84kds'/> 
     <author> 
      <name>John Doe</name> 
      <email>[email protected]</email> 
     </author> 
     <gd:comments> 
      <gd:feedLink href='https://www.google.com/calendar/feeds/johndoe%40gmail.com/public/full/lp0upnpndnkp0ruqht7ef84kds/comments'/> 
     </gd:comments> 
     <gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'/> 
     <gd:where valueString='9955 E Arapahoe Road, Englewood, CO 80112 (Go Subaru Arapahoe)'/> 
     <gd:who email='[email protected]' rel='http://schemas.google.com/g/2005#event.organizer' valueString='[email protected]'/> 
     <gd:when endTime='2011-09-29T11:30:00.000-06:00' startTime='2011-09-29T10:30:00.000-06:00'/> 
     <gd:transparency value='http://schemas.google.com/g/2005#event.opaque'/> 
     <gCal:anyoneCanAddSelf value='false'/> 
     <gCal:guestsCanInviteOthers value='true'/> 
     <gCal:guestsCanModify value='false'/> 
     <gCal:guestsCanSeeGuests value='true'/> 
     <gCal:sequence value='0'/> 
     <gCal:uid value='[email protected]'/> 
    </entry> 
</feed> 

想要的,正確的結果產生

<Events> 
    <Event> 
    <EventTitle>Oil Change</EventTitle> 
    <StartDateTime>2011-09-29 10:30:00</StartDateTime> 
    <EndDateTime>2011-09-29 11:30:00</EndDateTime> 
    <Who>John Doe</Who> 
    <Where>9955 E Arapahoe Road, Englewood, CO 80112 (Go Subaru Arapahoe)</Where> 
    <Status>http://schemas.google.com/g/2005#event.confirmed</Status> 
    </Event> 
</Events> 
+0

非常感謝。爲了我的學習,你能解釋一下你的「消除不必要的模板匹配文檔節點(/)」語句嗎? ''標籤內所有''標籤是否需要這個模板? – ABach

+0

@ABach:這是一個合理的,面向推送的風格。由於默認的XSLT處理可能會爲每個節點類型使用XSLT內置模板,程序員未爲其指定匹配的模板。內置模板的結果是將模板應用於所有子節點,並且如果當前節點是文本節點,則其字符串值將被複制到輸出。因此,我們依靠默認的XSLT處理來訪問'a:entry'元素,然後選擇與這些節點匹配的模板。我們阻止通過匹配的空模板複製文本節點。 –

+0

有道理。回到我原來的問題 - 把''標籤中的所有東西都包裹起來怎麼辦?可能丟失了一些明顯的東西...... – ABach

1

我會傾向於用一根火柴模板更換FORMATDATETIME模板:

<xsl:template match="@*" mode="formatDateTime"> 
    <xsl:value-of select="concat(substring-before(., 'T'), 
     ' ', substring-before(substring-after(., 'T'), '.'))" /> 
</xsl:template> 

並將呼叫更改爲

<StartDateTime> 
    <xsl:apply-templates select="$startDateTime" mode="formatDateTime"/> 
</StartDateTime> 
<EndDateTime> 
    <xsl:apply-templates select="$endDateTime" mode="formatDateTime"/> 
</EndDateTime> 

只是因爲呼叫模板語法太冗長。

(我也許會內聯變量 - 他們看不到增加值)。

+0

很好,很好的關於更換呼叫模板的說明;我自己討厭冗長,但不知道如何解決它。謝謝! – ABach