2013-03-26 97 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

相关问题