輸入I有:優化
我與產生RSS以下形式饋送SharePoint列表的工作:
<?xml version="1.0"?>
<rss>
<channel>
<!-- Irrelevant Fields -->
<item>
<title type="text">Title</title>
<description type="html">
<div><b>Field1:</b> Value 1</div>
<div><b>Field2:</b> Value 2</div>
<div><b>Field3:</b> Value 3</div>
<div><b>Field4:</b> Value 4</div>
<div><b>Field5:</b> Value 5</div>
</description>
</item>
<item>
<title type="text">Title</title>
<description type="html">
<div><b>Field1:</b> Value 1</div>
<div><b>Field3:</b> Value 3</div>
<div><b>Field4:</b> Value 4</div>
<div><b>Field5:</b> Value 5</div>
</description>
</item>
<item>
<title type="text">Title</title>
<description type="html">
<div><b>Field1:</b> Value 1</div>
<div><b>Field2:</b> Value 2</div>
<div><b>Field3:</b> Value 3</div>
<div><b>Field4:</b> Value 4</div>
<div><b>Field5:</b> Value 5</div>
</description>
</item>
<!-- More <item> elements -->
</channel>
</rss>
注意,<description>
元素似乎定義一組元素。此外,請注意,並非所有<description>
元素都包含「Field2」的標記。
我需要什麼:
我需要以下形式的XML:
<?xml version="1.0"?>
<Events>
<Event>
<Category>Title</Category>
<Field1>Value 1</Field1>
<Field2>Value 2</Field2>
<Field3>Value 3</Field3>
<Field4>Value 4</Field4>
<Field5>Value 5</Field5>
</Event>
<Event>
<Category>Title</Category>
<Field1>Value 1</Field1>
<Field2/>
<Field3>Value 3</Field3>
<Field4>Value 4</Field4>
<Field5>Value 5</Field5>
</Event>
<Event>
<Category>Title</Category>
<Field1>Value 1</Field1>
<Field2>Value 2</Field2>
<Field3>Value 3</Field3>
<Field4>Value 4</Field4>
<Field5>Value 5</Field5>
</Event>
</Events>
規則(更新):
- 這需要有一個XSLT 1.0解。
xxx:node-set
是唯一對我有效的擴展函數;這包括用其他語言編寫的擴展函數,例如C#或Javascript。- 如果缺少任何字段的信息,應該輸出一個空白元素。請注意,在我期望的輸出中,第二個
<Event>
元素中的空子元素爲<Field2>
。 - 我們不能假定字段名稱本身會遵循任何特定的模式;它們也可以被
<PeanutButter>
,<Jelly>
等
我到目前爲止有:
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl"
version="1.0">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/*">
<Events>
<xsl:apply-templates select="*/item"/>
</Events>
</xsl:template>
<xsl:template match="item[contains(description, 'Field2')]">
<Event>
<xsl:variable name="vElements">
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="description"/>
<xsl:with-param name="delimiter" select="' '"/>
</xsl:call-template>
</xsl:variable>
<Category>
<xsl:value-of select="title"/>
</Category>
<xsl:apply-templates
select="exsl:node-set($vElements)/*[normalize-space()]" mode="token"/>
</Event>
</xsl:template>
<!-- NOTE HOW THIS TEMPLATE IS NEARLY IDENTICAL TO THE LAST ONE,
MINUS THE BLANK <Field2>; THAT'S NOT VERY ELEGANT. -->
<xsl:template match="item[not(contains(description, 'Field2'))]">
<Event>
<xsl:variable name="vElements">
<xsl:call-template name="tokenize">
<xsl:with-param name="text" select="description"/>
<xsl:with-param name="delimiter" select="' '"/>
</xsl:call-template>
</xsl:variable>
<Category>
<xsl:value-of select="title"/>
</Category>
<xsl:apply-templates
select="exsl:node-set($vElements)/*[normalize-space()]" mode="token"/>
<Field2/>
</Event>
</xsl:template>
<xsl:template match="*" mode="token">
<xsl:element
name="{substring-after(
substring-before(normalize-space(), ':'),
'<div><b>')}">
<xsl:value-of
select="substring-before(
substring-after(., ':</b> '),
'</div>')"/>
</xsl:element>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="text"/>
<xsl:param name="delimiter" select="' '"/>
<xsl:choose>
<xsl:when test="contains($text,$delimiter)">
<xsl:element name="token">
<xsl:value-of select="substring-before($text,$delimiter)"/>
</xsl:element>
<xsl:call-template name="tokenize">
<xsl:with-param
name="text"
select="substring-after($text,$delimiter)"/>
<xsl:with-param
name="delimiter"
select="$delimiter"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="$text">
<xsl:element name="token">
<xsl:value-of select="$text"/>
</xsl:element>
</xsl:when>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
...主要生產:
<?xml version="1.0"?>
<Events>
<Event>
<Category>Title</Category>
<Field1>Value 1</Field1>
<Field2>Value 2</Field2>
<Field3>Value 3</Field3>
<Field4>Value 4</Field4>
<Field5>Value 5</Field5>
</Event>
<Event>
<Category>Title</Category>
<Field1>Value 1</Field1>
<Field3>Value 3</Field3>
<Field4>Value 4</Field4>
<Field5>Value 5</Field5>
<Field2/>
</Event>
<Event>
<Category>Title</Category>
<Field1>Value 1</Field1>
<Field2>Value 2</Field2>
<Field3>Value 3</Field3>
<Field4>Value 4</Field4>
<Field5>Value 5</Field5>
</Event>
</Events>
有兩個主要問題用我的解決方案:
- 感覺笨重;有重複的代碼,它似乎有點笨拙。我在想可能會發生一些優化?
- 請注意,它以不正確的順序輸出空的
<Field2>
元素並將它們放在底部。我認爲這很容易彌補,但我所有的解決方案都顯得很愚蠢,因此不包括在內。 :)
Ready,Set,Go!
我將不勝感激您的幫助與更優雅的解決方案(或者,至少,解決方案,修復問題#2上面)。謝謝!
結論
基於由@Borodin在他自己的解決方案提出的意見,我決定去與以下幾點:
<?xml version="1.0"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="exsl"
version="1.0">
<xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vFieldNames">
<name oldName="Field1" newName="fieldA" />
<name oldName="Field2" newName="fieldB" />
<name oldName="Field3" newName="fieldC" />
<name oldName="Field4" newName="fieldD" />
<name oldName="Field5" newName="fieldE" />
</xsl:variable>
<xsl:template match="/">
<events>
<xsl:apply-templates select="*/*/item" />
</events>
</xsl:template>
<xsl:template match="item">
<event>
<category>
<xsl:value-of select="title" />
</category>
<xsl:apply-templates select="exsl:node-set($vFieldNames)/*">
<xsl:with-param
name="pDescriptionText"
select="current()/description" />
</xsl:apply-templates>
</event>
</xsl:template>
<xsl:template match="name">
<xsl:param name="pDescriptionText" />
<xsl:variable
name="vRough"
select="substring-before(
substring-after($pDescriptionText, @oldName),
'div')"/>
<xsl:variable
name="vValue"
select="substring-before(
substring-after($vRough, '>'),
'<')"/>
<xsl:element name="{@newName}">
<xsl:value-of select="normalize-space($vValue)" />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
該解決方案增加了一個額外的層:它允許我很好地更改字段名稱(通過每個<name>
元素上的oldName
和newName
屬性)。
感謝所有回答!
是名總是從字面上'Field1'通過'Field5',或做他們需要從數據派生? – Borodin 2013-05-06 03:52:47
我建議編寫並使用一個簡單的單線程擴展函數,將其字符串參數解析爲XML並返回生成的XmlDocument。這對C#來說是微不足道的。 – 2013-05-06 04:12:51
@DimitreNovatchev:使用XSLT的' –
Borodin
2013-05-06 05:13:29