使用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>
我正在尝试在Service元素中使用ProviderName并将它们作为键和服务名称作为值。但我不知道如何使用它们。另请注意:
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.
所以我认为需要在ServiceProviders之后创建Service元素,但可能会复制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 :(得分:1)
考虑对Muenchian Grouping的这种调整,因为您不需要身份转换,而是重写为分组密钥定制的 Service 模板。另外,要按期间拆分@TypeName
个内容,请使用substring-before
和substring-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>