2017-03-17 49 views
0

使用xsl键解析某些唯一条目并使用键中的键值创建新节点。muenchian分组从xsl键创建节点

以下XML:

<Services> 
     <Service Name="Publish" TypeName="FzUDP.Publish" ProviderName="FzUDP" Position="69,102.533530201483" InitPriority="1"> 
      <Parameter Name="MultiCastIp" Value="224.0.0.0" /> 
      <Parameter Name="MultiCastPort" Value="61499" /> 
      <Parameter Name="Encryption" Value="0" /> 
      <Parameter Name="PacketFormat" Value="0" /> 
     </Service> 
     <Service Name="Subscribe" TypeName="FzUDP.Subscribe" ProviderName="FzUDP_1" Position="547,107.533530201483" InitPriority="2"> 
      <Parameter Name="MultiCastIp" Value="224.0.0.0" /> 
      <Parameter Name="MultiCastPort" Value="61499" /> 
      <Parameter Name="Decryption" Value="0" /> 
      <Parameter Name="PacketFormat" Value="0" /> 
     </Service> 
<Service Name="Subscribe2" TypeName="FzUDP.Subscribe" ProviderName="FzUDP_1" Position="547,107.533530201483" InitPriority="2"> 
      <Parameter Name="MultiCastIp" Value="224.0.0.0" /> 
      <Parameter Name="MultiCastPort" Value="61499" /> 
      <Parameter Name="Decryption" Value="0" /> 
      <Parameter Name="PacketFormat" Value="0" /> 
     </Service> 
</Services> 

需要被转化为:

<ServiceProviders> 
<ServiceProvider Name="FzUDP" TypeName="FzUDP"> 
    <Services> 
     <Service Name="Publish" TypeName="Publish" InitPriority="1"> 
      <Parameter Name="MultiCastIp" Value="224.0.0.0" /> 
      <Parameter Name="MultiCastPort" Value="61499" /> 
      <Parameter Name="Encryption" Value="0" /> 
      <Parameter Name="PacketFormat" Value="0" /> 
     </Service> 
     <Service Name="Subscribe" TypeName="Subscribe" InitPriority="2"> 
      <Parameter Name="MultiCastIp" Value="224.0.0.0" /> 
      <Parameter Name="MultiCastPort" Value="61499" /> 
      <Parameter Name="Decryption" Value="0" /> 
      <Parameter Name="PacketFormat" Value="0" /> 
     </Service> 
    </Services> 
</ServiceProvider> 
<ServiceProvider Name="FzUDP_1" TypeName="FzUDP"> 
    <Services> 
     <Service Name="Subscribe2" TypeName="Subscribe" InitPriority="2"> 
      <Parameter Name="MultiCastIp" Value="224.0.0.0" /> 
      <Parameter Name="MultiCastPort" Value="61499" /> 
      <Parameter Name="Decryption" Value="0" /> 
      <Parameter Name="PacketFormat" Value="0" /> 
     </Service> 
    </Services> 
</ServiceProvider> 

的XSL代码我想出迄今:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> 
<xsl:output method="xml" indent="yes"/> 

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

<xsl:key name="uniqueProviders" match="Service[@ProviderName]" use="Service[@Name]" /> 


<xsl:template match="Services"> 
<ServiceProviders> 
    <xsl:for-each select=?> 


    </xsl:for-each> 


</ServiceProviders> 
</xsl:template> 
</xsl:stylesheet> 

我正在尝试使用Pro viderName放入Service元素中,并将它们作为键和服务名称作为值。但我不确定如何使用它们。另外请注意:

a. Attribute Position is not required in the transformed XML. 
b. The TypeName attribute of the ServiceProvider element is the first '.' split of the TypeName attribute of the Service element. 

所以我认为Service元素需要在ServiceProviders之后创建,但可能会复制Parameter元素。我从哪里出发?

编辑1:我得到了以下使用XSLT 2.0

<?xml version="1.0" encoding="utf-8"?> 

<xsl:stylesheet version="2.0" 
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:saxon="http://saxon.sf.net/" 
       extension-element-prefixes="saxon" 
    xmlns:bootFile="http://tempuri.org/BootfileDefinition" 
       xmlns:apps="http://tempuri.org/FZDevice"> 

    <xsl:output method="xml" indent="yes"/> 


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



    <xsl:template match ="//apps:Services"> 
    <xsl:element name="ServiceProviders"> 
     <xsl:for-each-group select="//apps:Service" group-by="//apps:Service/@ProviderName"> 
     <xsl:element name="ServiceProvider"> 
      <xsl:attribute name="Name"> 
      <xsl:value-of select="current-grouping-key()"/> 
      </xsl:attribute> 

      <xsl:attribute name="TypeName"> 
      <xsl:value-of select="tokenize(current-group()[1]/@TypeName, '\.')[1]"/> 
      </xsl:attribute> 

      <xsl:for-each select="current-group()"> 
      <xsl:element name="Service"> 

       <xsl:attribute name="Name"> 
       <xsl:value-of select="@Name"/> 
       </xsl:attribute> 

       <xsl:attribute name="TypeName"> 
       <xsl:value-of select="tokenize(@TypeName, '\.')[2]"/> 
       </xsl:attribute> 

       <xsl:attribute name="InitPriority"> 
       <xsl:value-of select="@InitPriority"/> 
       </xsl:attribute> 

       <xsl:copy-of select="//apps:Parameter"/> 

      </xsl:element> 
      </xsl:for-each> 

     </xsl:element> 
     </xsl:for-each-group> 
    </xsl:element> 
    </xsl:template> 


</xsl:stylesheet> 

需要注意的是有前缀的元素名称的命名空间。我将在输出XML中摆脱它们,并希望有人能够帮助我在XSLT 1.0中做同样的事情。

+0

你可以用几句话解释一下这里的实际问题?看起来你想通过'ProviderName'属性对服务进行分组。为什么有必要标记任何东西?如果您使用XSLT 2.0,为什么还需要使用Muenchian分组?为什么在你的结果中'FzUDP_1'下的'Subscribe2'?当输入中没有这样的元素时,为什么你有一个匹配'FourZeroBootFile/Runtime'的模板? –

+0

是的,这是正确的。我已经解决了这个问题中的错误。那么在XSLT 2.0中有更好的方法吗? – meonstackexchange

+0

我仍然不明白你的输出。但是如果我说的是真的,那么你可以简单地使用use <'。 SO上有很多这样的分组例子。 –

回答

1

考虑对Muenchian分组进行调整,因为您不需要进行身份转换,但需要重写服务为分组密钥量身定制的模板。此外,要按期间分割@TypeName内容,请使用substring-beforesubstring-after函数。看起来你想<xsl:key>是一个连接@ProviderName@TypeName(周期部分之前)。

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
           xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:key name="uniqueProviders" match="Service" use="concat(@ProviderName, substring-before(@TypeName, '.'))" /> 

    <xsl:template match="/Services"> 
     <ServiceProviders> 
      <xsl:apply-templates select="Service"/> 
     </ServiceProviders> 
    </xsl:template> 

    <xsl:template match="Service[generate-id() = generate-id(key('uniqueProviders', concat(@ProviderName, substring-before(@TypeName, '.')))[1])]"> 
     <ServiceProvider Name="{@ProviderName}" TypeName="{substring-before(@TypeName, '.')}"> 
      <xsl:for-each select="key('uniqueProviders', concat(@ProviderName, substring-before(@TypeName, '.')))"> 
       <Service Name="{@Name}" TypeName="{substring-after(@TypeName, '.')}" InitPriority="{@InitPriority}"> 
        <xsl:copy-of select="*"/> 
       </Service>  
      </xsl:for-each> 
     </ServiceProvider> 
    </xsl:template>  

</xsl:stylesheet> 

输出

<?xml version="1.0" encoding="utf-8"?> 
<ServiceProviders> 
    <ServiceProvider Name="FzUDP" TypeName="FzUDP"> 
    <Service Name="Publish" TypeName="Publish" InitPriority="1"> 
     <Parameter Name="MultiCastIp" Value="224.0.0.0" /> 
     <Parameter Name="MultiCastPort" Value="61499" /> 
     <Parameter Name="Encryption" Value="0" /> 
     <Parameter Name="PacketFormat" Value="0" /> 
    </Service> 
    </ServiceProvider> 
    <ServiceProvider Name="FzUDP_1" TypeName="FzUDP"> 
    <Service Name="Subscribe" TypeName="Subscribe" InitPriority="2"> 
     <Parameter Name="MultiCastIp" Value="224.0.0.0" /> 
     <Parameter Name="MultiCastPort" Value="61499" /> 
     <Parameter Name="Decryption" Value="0" /> 
     <Parameter Name="PacketFormat" Value="0" /> 
    </Service> 
    <Service Name="Subscribe2" TypeName="Subscribe" InitPriority="2"> 
     <Parameter Name="MultiCastIp" Value="224.0.0.0" /> 
     <Parameter Name="MultiCastPort" Value="61499" /> 
     <Parameter Name="Decryption" Value="0" /> 
     <Parameter Name="PacketFormat" Value="0" /> 
    </Service> 
    </ServiceProvider> 
</ServiceProviders>