2013-03-26 53 views
0

我的XML結構是這樣如何使用xsl從多個具有相同名稱的節點創建一個節點?

<Client> 
    <Document> 
    <service class="ABC"> 
     <author name="x"/> 
     <Details> 
     ... 
     </Details> 
    </service> 
    </Document> 
    <Document> 
    <service class="ABC"> 
     <author name="x"/> 
     <Details> 
     ... 
     </Details> 
    </service> 
    </Document> 
    <Document> 
    <service class="ABC"> 
     <author name="x"/> 
     <Details> 
     ... 
     </Details> 
    </service> 
    </Document>' 
</Client> 

我希望它像

<Client> 
    <Document> 
    <service class="ABC"> 
     <author name="x"/> 
     <Details> 
     ... 
     </Details> 
    </service> 
    </Document> 
    <Document> 
    <service class="ABC"> 
     <author name="x"/> 
     <Details> 
     ... 
     </Details> 
    </service> 
    </Document> 
    <Document> 
    <service class="ABC"> 
     <author name="x"/> 
     <Details> 
     ... 
     </Details> 
    </service> 
    </Document>' 
    <component> 
    <service class="ABC"> 
     <author name="x"/> 
    </service> 
    </component>' 
</Client> 

我的XSL文件包含

<xsl:template match="//v3:Client"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
     <component> 
     <service class=""> 
      <xsl:apply-templates select="//v3:Client/v3:Document/v3:service/v3:author"/> 
     </service> 
     </component> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="//v3:Client/v3:component/v3:service"> 
    <xsl:element name="service" namespace="urn:hl7-org:v3"> 
     <xsl:attribute name="class"> 
     <xsl:value-of select="//v3:Client/v3:Document/v3:service/@class"/> 
     </xsl:attribute> 
    </xsl:element> 
    </xsl:template> 

但它不會給所需的輸出。它的輸出像

 
Client 
    Document 
    service class="ABC" 
     author name="x" 
     details 
     ... 
     details 
    service 
    Document 
    Document 
    service class="ABC" 
     author name="x" 
     details 
     ... 
     details 
    service 
    Document 
    Document 
    service class="ABC" 
     author name="x" 
     details 
     ... 
     details 
    service 
    Document 
    component 
    service class="" 
     author name="x" 
    service 
    service class="" 
     author name="x" 
    service 
    service class="" 
     author name="x" 
    service 
    component 
Client 

我是新來的xsl。任何人都可以幫我解決這個問題嗎?

回答

0

如果你想輸出你組件元素的不同服務元素,那麼在XSTL1.0你需要使用一項名爲Muenchian Grouping的技術。我假設屬性唯一地標識一個服務,所以你會通過定義一鍵查找服務,像這樣

<xsl:key name="service" match="service" use="@class" /> 

然後啓動,創建組件元素時,得到不同的服務元素你已經看過所有這些元素,但只能選擇那些首先出現在給定的屬性中的鍵。

<xsl:apply-templates 
    select="Document/service[generate-id() = generate-id(key('service', @class)[1])]" 
    mode="component" /> 

內的服務元素相匹配的模板,你可以直接輸出的細節要求。在你的示例中,它看起來像你只想要這裏的作者元素,而不是的細節

<xsl:template match="service" mode="component"> 
    <xsl:copy> 
    <xsl:apply-templates select="author|@*"/> 
    </xsl:copy> 
</xsl:template> 

採用模式是因爲你只想要這個,當你outputing的compenent元素模板匹配。

以下是完整的XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
<xsl:key name="service" match="service" use="@class" /> 

<xsl:template match="Client"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    <component> 
     <xsl:apply-templates select="Document/service[generate-id() = generate-id(key('service', @class)[1])]" mode="component" /> 
    </component> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="service" mode="component"> 
    <xsl:copy> 
     <xsl:apply-templates select="author|@*"/> 
    </xsl:copy> 
</xsl:template> 

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

當適用於您的示例XML,下面是輸出

<Client> 
    <Document> 
     <service class="ABC"> 
     <author name="x"/> 
     <Details> ... </Details> 
     </service> 
    </Document> 
    <Document> 
     <service class="ABC"> 
     <author name="x"/> 
     <Details> ... </Details> 
     </service> 
    </Document> 
    <Document> 
     <service class="ABC"> 
     <author name="x"/> 
     <Details> ... </Details> 
     </service> 
    </Document> 
    <component> 
     <service class="ABC"> 
     <author name="x"/> 
     </service> 
    </component> 
</Client> 
+0

謝謝你的回覆。 這裏問題是所有的服務節點都有相同的類值。 – learner 2013-03-27 06:15:01

+0

您可以編輯您的問題以顯示服務節點具有不同類值的示例嗎?謝謝! – 2013-03-27 08:22:18

+0

只是一個小的變化,它的工作。 非常感謝。所有的答案都很有幫助,但這個解決方案最合適。 謝謝大家。 – learner 2013-03-27 08:58:16

0

使用group-by特徵:上述

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="xml" indent="yes" /> 

    <xsl:template match="/Client"> 

    <xsl:copy-of select="Document" /> 

    <!-- Group nodes by attribute value, produce one <component> 
     per each group --> 
    <xsl:for-each-group select="Document" group-by="service/@class"> 
     <component> 
     <xsl:copy-of select="./service" /> 
     </component> 
    </xsl:for-each-group> 

    </xsl:template> 

</xsl:stylesheet> 

樣式表產生每每個Document class=""屬性值的一個<component>

+0

非常感謝你的快速回復。 我只想要一個節點,並且想要將所有節點合併爲一個節點。我也想從節點設置屬性類的值。 – learner 2013-03-26 09:57:15

+0

我使用的是xsl:stylesheet version =「1.0」。我認爲它不支持'xsl:for-each-group'作爲孩子。 你能幫我嗎? – learner 2013-03-26 10:04:28

0

如果您無權訪問group-by,則可以考慮使用following-sibling::軸。

換句話說,你正在尋找的東西是這樣的:

<component> 
    <xsl:apply-templates select="Document/service[@class != following-sibling::service/@class]" mode="component" /> 
</component> 

<xsl:template match="service" mode="component"> 
    <service class="{@class}"> 
     <!-- etc. --> 
    </service> 
</xsl:template> 
+0

謝謝你的回覆。 '以下兄弟'不起作用。它給出錯誤'有多個根元素'。 我xml中的每個服務節點都具有相同的類值。 – learner 2013-03-26 11:13:43

+0

我需要看到你的xslt能夠對此發表評論。也許你可以發佈一個GitHub gist鏈接或類似的東西? – Marcus 2013-03-26 11:18:46

相關問題