Bạn có thể thử làm theo
SELECT @xml.query('
element a {
for $node in /a/*[local-name() != "d"]
return $node
}');
Nhưng nó có thể không phù hợp nếu XML thực của bạn phức tạp hơn và bạn phải loại trừ nút ở mức lồng nhau sâu hơn.
Nói một cách trung thực, tôi không nghĩ rằng XQuery là công cụ tốt cho các loại nhiệm vụ như vậy. Về bản chất, chúng ta có XML và chúng ta cần loại bỏ một nút ở đâu đó bên trong, tức là chúng ta cần chuyển đổi nó. Công cụ phù hợp hơn, tôi nghĩ, là các phép biến đổi XSL. Thật không may, SQL Server không có các khả năng XSLT tích hợp (tuy nhiên, nó có thể được thêm thông qua chức năng SQLCLR).
Đây là cách cơ thể của XSL để giải quyết nhiệm vụ này có thể trông như thế nào
<!-- Skip "d" under "a" -->
<xsl:template match="a/d" />
<!-- Apply identity transform to other nodes -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
Nó sẽ hoạt động cho a
phần tử nằm ở bất kỳ đâu trong XML, không chỉ ở gốc.
Hàm SQLCLR để thực hiện chuyển đổi XSL không tham số có thể đơn giản như vài dòng mã C #
[SqlFunction(Name = "XslTransform")]
public static SqlXml XslTransform(SqlXml xml, SqlXml xsl)
{
if (xml.IsNull || xsl.IsNull)
return SqlXml.Null;
var xslt = new XslCompiledTransform();
using (var xr = xsl.CreateReader())
xslt.Load(xr);
var xws = new XmlWriterSettings
{
Encoding = Encoding.Unicode,
OmitXmlDeclaration = true
};
var output = new MemoryStream();
using (var xw = XmlWriter.Create(output, xws))
using (var xr = xml.CreateReader())
{
xslt.Transform(xr, null, xw);
xw.Flush();
}
output.Seek(0, SeekOrigin.Begin);
return new SqlXml(output);
}
Nó nên được khai báo trong cơ sở dữ liệu như
CREATE FUNCTION SQLCLR.XslTransform
(
@xml xml,
@xsl xml
)
RETURNS xml
AS EXTERNAL NAME [AssemblyName].[ClassName].[XslTransform];
GO
Và nó có thể được sử dụng sau đó như là
DECLARE
@xml xml = N'(Your XML goes here)',
@xsl xml = N'(Your XSL goes here)';
SELECT SQLCLR.XslTransform(@xml, @xsl);