将 xml 中的配对空节点替换为自闭合节点



我有一些xml,其中一部分看起来像这样:

<BasicInfo>
<Foo>80</Foo>
<Bar>
</Bar>
</BasicInfo>

我想用单个自闭合节点替换所有空节点打开和关闭对(如上面的<Bar>),给出如下结果:

<BasicInfo>
<Foo>80</Foo>
<Bar />
</BasicInfo>

我知道在 xml 中,两者是等效的,xslt 会选择它想要输出空节点的方式等等,但我有很多空节点,两种解释中的预期文件大小差异足够大,值得担心;我希望尽可能高效地存储 xml。

上面的 xml 是从 SQL Server 创建的,然后用另一个 XSLT 进行转换,该 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 的了解很差,这意味着我无法改变针对我需求的解决方案(需要很长时间才能解决上述问题!似乎类似于规范化空间的东西是要走的路?我真的很感激一些帮助!

铌。XML 由 SQL Server 2008 R2 使用FOR XML PATH生成,XSLT 脚本存储在服务器上的 xml 列中;SSIS 2008 中操作数类型 XSLT 的 XML 任务应用转换。

给定:

.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元素包含的仅空格文本节点,处理器将自动输出空元素作为自关闭标记。

NULL的正常行为是完全省略该元素...

如果我做对了,你放置ELEMENTS XSINIL来强制引擎引入所有元素,即使在NULL的情况下.

一个黑客技巧可能是删除如下所示的属性:

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;

最新更新