对这些问题的基本性质表示道歉 - 我对XSLT(以及Stack Overflow)也是全新的。
我需要转换Sharepoint Web服务返回的以下XML:
<GetGroupCollectionFromUser xmlns=
"http://schemas.microsoft.com/sharepoint/soap/directory/">
<Groups>
<Group ID="3" Name="Group1" Description="Description" OwnerID="1"
OwnerIsUser="False" />
<Group ID="15" Name="Group2" Description="Description"
OwnerID="12" OwnerIsUser="True" />
<Group ID="16" Name="Group3" Description="Description"
OwnerID="7" OwnerIsUser="False" />
</Groups>
</GetGroupCollectionFromUser>
进入这个:
<GetGroupCollectionFromUser xmlns=
"http://schemas.microsoft.com/sharepoint/soap/directory/">
<Groups>
<Group Name="Group1" />
<Group Name="Group2" />
<Group Name="Group3" />
</Groups>
</GetGroupCollectionFromUser>
基本上,我需要删除除Name之外的每个Group元素的所有属性。经过大量的研究和修补,特别是从原始XML中删除命名空间声明后,我想出了一些让我几乎完全符合我需要的东西:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="no"/>
<xsl:template match="/GetGroupCollectionFromUser">
<xsl:copy>
<xsl:apply-templates select="Groups" />
</xsl:copy>
</xsl:template>
<xsl:template match="Groups">
<xsl:copy>
<xsl:apply-templates select="Group" />
</xsl:copy>
</xsl:template>
<xsl:template match="Group">
<xsl:copy>
<xsl:apply-templates select="@Name" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
但是,上面给出了作为文本插入Group元素的Name属性的值,而不是Name属性,如下所示:
<GetGroupCollectionFromUser>
<Groups>
<Group>Group1</Group>
<Group>Group2</Group>
<Group>Group3</Group>
</Groups>
</GetGroupCollectionFromUser>
这最终将由期望以属性为中心的XML的第三方应用程序使用。我确定我错过了一些令人尴尬的东西,但无论我用它做什么,我似乎都无法仅仅引入Name属性。两个问题:
如何更改XSLT以返回每个Group元素的Name属性,而不是将其值作为文本返回?
而且,如何正确处理命名空间?当我将它包含在XSLT中时,尝试基于我在这里和网上其他地方找到的示例的几种方法,我什么也得不到。
提前感谢任何建议。
答案 0 :(得分:3)
处理这些情况的方法是重写身份转换:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msft="http://schemas.microsoft.com/sharepoint/soap/directory/">
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="msft:Group">
<xsl:copy>
<xsl:apply-templates select="@Name" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
输出:
<GetGroupCollectionFromUser
xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/">
<Groups>
<Group Name="Group1" />
<Group Name="Group2" />
<Group Name="Group3" />
</Groups>
</GetGroupCollectionFromUser>
请注意,输出正确命名空间。
由于其简单性和灵活性,该解决方案是优选的。除非存在指定备用行为的覆盖,否则将按原样复制所有节点和属性。
答案 1 :(得分:2)
如果你不在这里使用xsl:copy
,我认为你会变得更容易。试试这个:
<xsl:template match="Groups/*">
<xsl:element name="Group">
<xsl:attribute name="Name">
<xsl:value-of select="@Name" />
</xsl:attribute>
</xsl:element>
</xsl:template>
对第二个问题的回答是FAQ。声明命名空间并在xsl中使用声明的前缀。最终解决方案:
<xsl:stylesheet version="1.0"
xmlns:myns="http://schemas.microsoft.com/sharepoint/soap/director/"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="no"/>
<xsl:template match="/myns:GetGroupCollectionFromUser">
<Groups>
<xsl:apply-templates select="myns:Groups" />
</Groups>
</xsl:template>
<xsl:template match="myns:Groups/*">
<xsl:element name="Group">
<xsl:attribute name="Name">
<xsl:value-of select="@Name" />
</xsl:attribute>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
答案 2 :(得分:2)
这可能是正确产生所需结果的最短转换之一:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="@*[not(name()='Name')]"/>
</xsl:stylesheet>
应用于提供的XML文档:
<GetGroupCollectionFromUser xmlns=
"http://schemas.microsoft.com/sharepoint/soap/directory/">
<Groups>
<Group ID="3" Name="Group1" Description="Description" OwnerID="1" OwnerIsUser="False" />
<Group ID="15" Name="Group2" Description="Description" OwnerID="12" OwnerIsUser="True" />
<Group ID="16" Name="Group3" Description="Description" OwnerID="7" OwnerIsUser="False" />
</Groups>
</GetGroupCollectionFromUser>
产生了想要的正确结果:
<GetGroupCollectionFromUser xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/">
<Groups>
<Group Name="Group1"/>
<Group Name="Group2"/>
<Group Name="Group3"/>
</Groups>
</GetGroupCollectionFromUser>
<强>解释强>:
身份规则(模板)按“原样”复制每个节点。
只有一个模板会覆盖身份规则。它匹配名称不是“Name”的任何属性。模板的主体为空,这导致未复制任何匹配的属性。
使用和覆盖标识规则是最基本和最强大的XSLT设计模式。了解它here 。
答案 3 :(得分:0)
这似乎对我有用:
<xsl:template match="Group">
<xsl:copy>
<xsl:attribute name="Name">
<xsl:apply-templates select="@Name" />
</xsl:attribute>
</xsl:copy>
</xsl:template>