我有一些xml,其中一部分看起来像这样:
<BasicInfo>
<Foo>80</Foo>
<Bar>
</Bar>
</BasicInfo>
我想用单个自闭节点替换所有空节点开关对(如上面的<Bar>
),得到这样的结果:
<BasicInfo>
<Foo>80</Foo>
<Bar />
</BasicInfo>
我知道在xml中,两者是等价的,xslt会选择输出空节点的方式等等,但我有很多空节点,两个解释中预期的文件大小差异很大足以值得担心;我希望尽可能有效地存储xml。
上面的xml是从SQL Server创建的,然后用另一个XSLT转换,删除了SQL Server 2008留下的所有“xsi:nil”值和xmlns声明:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="*">
<xsl:element name="{local-name(.)}">
<xsl:apply-templates select="@* | node()" />
</xsl:element>
</xsl:template>
<xsl:template match="@*">
<xsl:attribute name="{local-name(.)}">
<xsl:value-of select="." />
</xsl:attribute>
</xsl:template>
<xsl:template match="@*[local-name(.)='noNamespaceSchemaLocation']" />
<xsl:template xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" match="@xsi:nil" />
</xsl:stylesheet>
正是这个样式表将开 - 关对留下 - 有没有办法强制它留下自闭节点,或者让新的xslt自己产生这种效果?
遗憾的是,删除节点不是一个选择:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" version="1.0">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<!--Remove all the empty nodes-->
<!--copy nodes-->
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*" />
</xsl:copy>
</xsl:template>
<!--match only those with no contents at all-->
<xsl:template match="*[not(@*|*|comment()|processing-instruction()) and normalize-space()='']" />
<!--now check all those that have existing but empty children and don't return the children if they are empty-->
<xsl:template match="*">
<xsl:copy>
<xsl:if test="descendant::text()">
<xsl:apply-templates select="node()" />
</xsl:if>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
但这是我最接近的。我发现其他人都在问这个问题,但是我对xslt的了解很少,这意味着我无法改变满足我需求的解决方案(需要很长时间才能解决上面的问题!)。看起来像标准化空间这样的东西是要走的路?我真的很感激一些帮助!
NB。 xml由SQL Server 2008 R2使用FOR XML PATH
生成,XSLT脚本存储在服务器上的xml列中; SSIS 2008中的操作数类型为XSLT的XML任务应用转换。
答案 0 :(得分:1)
假设:
<强> XML 强>
<BasicInfo>
<Foo>80</Foo>
<Bar>
</Bar>
</BasicInfo>
以下样式表:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
将返回:
<?xml version="1.0" encoding="UTF-8"?>
<BasicInfo>
<Foo>80</Foo>
<Bar/>
</BasicInfo>
<强>解释强>
<xsl:strip-space elements="*"/>
指令将删除Bar
元素包含的仅空白文本节点,处理器将自动输出一个空元素作为自关闭标记。
答案 1 :(得分:1)
NULL
的正常行为是完全省略该元素......
如果我做对了,你就ELEMENTS XSINIL
强制引擎引入所有元素,即使是NULL
。
一个hacky技巧可能是删除像这里的属性:
CREATE TABLE #Demo ( Id INT IDENTITY(1,1) NOT NULL
,Value1 VARCHAR(30) NOT NULL
,Value2 VARCHAR(30) NULL );
INSERT #Demo(Value1,Value2)
VALUES('Bar',NULL);
WITH XMLNAMESPACES ('http://tempuri.org/MySchema.xsd' AS xsd)
SELECT This.Id
,( SELECT T.Value1
,T.Value2
FROM #Demo T
WHERE T.Id = This.Id
FOR XML PATH('BasicInfo'),ELEMENTS XSINIL,TYPE) AS TheXml
INTO #Demo2
FROM #Demo AS This;
UPDATE #Demo2 SET TheXml.modify('delete (//*/@*[local-name()="nil"])');
SELECT * FROM #Demo2
GO
DROP TABLE #Demo
DROP TABLE #Demo2;