AKTUALISIEREN:
Ich habe den Code sowie das Eingabe- und Ausgabe-XML in der folgenden Beispielabfrage aktualisiert, um die neueste Anforderung widerzuspiegeln, die in einem Kommentar zu @ Mikaels feiner Antwort angegeben ist:
Wertelement nicht erstellen, wenn @Value leer ist oder nicht existiert
Während ein einzelner Ausdruck dieser neuen Variante korrekt entsprechen kann, scheint es keine Möglichkeit zu geben, das leere <Value/>
Element in einem einzelnen Durchgang wegzulassen , da die bedingte Logik in der Ersetzungszeichenfolge nicht zulässig ist. Daher habe ich dies als zweiteilige Modifikation angepasst: einen Durchgang, um die nicht leeren @Value
Attribute zu erhalten, und einen Durchgang, um die leeren @Value
Attribute zu erhalten. Es war nicht erforderlich, mit dem <Element>
Fehlen des @Value
Attributs umzugehen, da der Wunsch besteht, das <Value>
Element sowieso nicht zu haben .
Eine Möglichkeit besteht darin, das XML als regulären String zu behandeln und basierend auf einem Muster zu transformieren. Dies kann leicht mit regulären Ausdrücken (insbesondere der Funktion "Ersetzen") erreicht werden, die über den SQLCLR-Code verfügbar gemacht werden können.
Im folgenden Beispiel wird die skalare UDF RegEx_Replace aus der SQL # -Bibliothek verwendet (deren Autor ich bin, aber diese RegEx-Funktion ist in der kostenlosen Version zusammen mit vielen anderen verfügbar):
DECLARE @SomeXml XML;
SET @SomeXml = N'<Root attr1="val1" attr2="val2">
<Elements>
<Element Code="1" Value="aaa" ExtraData="extra1" />
<Element Code="22" Value="bbb" ExtraData="extra2" />
<Element Code="333" Value="ccc" ExtraData="extra3" />
<Element Code="4444" Value="" ExtraData="extra4" />
<Element Code="55555" ExtraData="extra5" />
</Elements>
<ExtraData>
<Something Val="1">qwerty A</Something>
<Something Val="2">qwerty B</Something>
</ExtraData>
</Root>';
DECLARE @TempStringOfXml NVARCHAR(MAX),
@Expression NVARCHAR(4000),
@Replacement NVARCHAR(4000);
SET @TempStringOfXml = CONVERT(NVARCHAR(MAX), @SomeXml);
PRINT N'Original: ' + @TempStringOfXml;
---
SET @Expression =
N'(<Element Code="[^"]+")\s+Value="([^"]+)"\s+(ExtraData="[^"]+")\s*/>';
SET @Replacement = N'$1 $3><Value>$2</Value></Element>';
SELECT @TempStringOfXml = SQL#.RegEx_Replace(@TempStringOfXml, @Expression,
@Replacement, -1, 1, '');
PRINT '-------------------------------------';
PRINT N'Phase 1: ' + @TempStringOfXml; -- transform Elements with a non-empty @Value
---
SET @Expression = N'(<Element Code="[^"]+")\s+Value=""\s+(ExtraData="[^"]+")\s*/>';
SET @Replacement = N'$1 $2 />';
SELECT @TempStringOfXml = SQL#.RegEx_Replace(@TempStringOfXml, @Expression,
@Replacement, -1, 1, '');
PRINT '-------------------------------------';
PRINT N'Phase 2: ' + @TempStringOfXml; -- transform Elements with an empty @Value
SELECT CONVERT(XML, @TempStringOfXml); -- prove that this is valid XML
Die PRINT
Anweisungen dienen nur dazu, den Vergleich nebeneinander auf der Registerkarte "Nachrichten" zu vereinfachen. Die resultierende Ausgabe ist (ich habe das ursprüngliche XML ein wenig geändert, um deutlich zu machen, dass nur die gewünschten Teile berührt wurden und sonst nichts):
Original: <Root attr1="val1" attr2="val2"><Elements><Element Code="1" Value="aaa" ExtraData="extra1"/><Element Code="22" Value="bbb" ExtraData="extra2"/><Element Code="333" Value="ccc" ExtraData="extra3"/><Element Code="4444" Value="" ExtraData="extra4"/><Element Code="55555" ExtraData="extra5"/></Elements><ExtraData><Something Val="1">qwerty A</Something><Something Val="2">qwerty B</Something></ExtraData></Root>
-------------------------------------
Phase 1: <Root attr1="val1" attr2="val2"><Elements><Element Code="1" ExtraData="extra1"><Value>aaa</Value></Element><Element Code="22" ExtraData="extra2"><Value>bbb</Value></Element><Element Code="333" ExtraData="extra3"><Value>ccc</Value></Element><Element Code="4444" Value="" ExtraData="extra4"/><Element Code="55555" ExtraData="extra5"/></Elements><ExtraData><Something Val="1">qwerty A</Something><Something Val="2">qwerty B</Something></ExtraData></Root>
-------------------------------------
Phase 2: <Root attr1="val1" attr2="val2"><Elements><Element Code="1" ExtraData="extra1"><Value>aaa</Value></Element><Element Code="22" ExtraData="extra2"><Value>bbb</Value></Element><Element Code="333" ExtraData="extra3"><Value>ccc</Value></Element><Element Code="4444" ExtraData="extra4" /><Element Code="55555" ExtraData="extra5"/></Elements><ExtraData><Something Val="1">qwerty A</Something><Something Val="2">qwerty B</Something></ExtraData></Root>
Wenn Sie ein Feld in einer Tabelle aktualisieren möchten, können Sie Folgendes anpassen:
DECLARE @NonEmptyValueExpression NVARCHAR(4000),
@NonEmptyValueReplacement NVARCHAR(4000),
@EmptyValueExpression NVARCHAR(4000),
@EmptyValueReplacement NVARCHAR(4000);
SET @NonEmptyValueExpression =
N'(<Element Code="[^"]+")\s+Value="([^"]+)"\s+(ExtraData="[^"]+")\s*/>';
SET @NonEmptyValueReplacement = N'$1 $3><Value>$2</Value></Element>';
SET @EmptyValueExpression =
N'(<Element Code="[^"]+")\s+Value=""\s+(ExtraData="[^"]+")\s*/>';
SET @EmptyValueReplacement = N'$1 $2 />';
UPDATE tbl
SET XmlField = SQL#.RegEx_Replace4k(
SQL#.RegEx_Replace4k(
CONVERT(NVARCHAR(4000), tbl.XmlField),
@NonEmptyValueExpression,
@NonEmptyValueReplacement,
-1, 1, ''),
@EmptyValueExpression,
@EmptyValueReplacement,
-1, 1, '')
FROM SchemaName.TableName tbl
WHERE tbl.XmlField.exist('Root/Elements/Element/@Value') = 1;
<Value>
Elemente pro Element<Element>
. Wenn nicht, führt das Verschieben des Attributs in ein Element nur zu aufgeblähterem und möglicherweise weniger effizientem XML.