SQL Server ändert die XML-Struktur beim Einfügen

15

Ich füge einige XML-Daten in eine XML-Spalte in SQL Server ein, aber nachdem die Daten eingefügt wurden, wurden sie von SQL Server geändert. Hier sind die Daten, die ich einfüge

              <xsl:value-of select="name/n/given" />
            <xsl:text> </xsl:text>
          <xsl:value-of select="name/n/family" />

Wenn ich es zurücklese, sieht es so aus

              <xsl:value-of select="name/n/given" />
          <xsl:text />
          <xsl:value-of select="name/n/family" />

Achten Sie auf die zweite Zeile. Dies ist ein Problem, da sich dadurch die Ausgabe der XSLT-Transformation ändert. Das erste Beispiel erzeugt ein Leerzeichen zwischen Vorname und Familienname, während das zweite kein Leerzeichen erzeugt, also wie JohnJohnsen, während das erste wie John Johnsen ist.

Gibt es eine Möglichkeit, dies zu lösen?

Herr Zach
quelle
Dies ist ein Problem, da sich dadurch die Ausgabe der XSLT-Transformation ändert. In der ersten Zeile wird ein Leerzeichen zwischen Vorname und Familienname eingefügt, während in der zweiten Zeile kein Leerzeichen zwischen dem Namen und dem Namen von JohnJohnsen eingefügt wird. In der ersten Zeile wird John Johnsen eingefügt
Mr Zach
hmhm, richtiger raum es ist "" aber nicht nur ein raum wie in diesem kommentar (du kannst es nicht sehen)
a_vlad
1
Vielleicht könnten Sie ein Steuerzeichen verwenden, das in den Daten nicht vorhanden ist (wie _oder ~) und dieses dann zur Präsentationszeit durch ein Leerzeichen ersetzen.
Aaron Bertrand

Antworten:

25

Sie können xml:space = "preserve"auf den Knoten verwenden, auf denen Sie den Speicherplatz behalten möchten. Die Verwendung von xml: space ist "nur ein Signal der Absicht", aber SQL Server ist hier nett zu uns.

Für einen Knoten

declare @X xml =
'<root>
  <element xml:space = "preserve"> </element>
  <element> </element>
</root>'

select @X;

Ergebnis:

<root>
  <element xml:space="preserve"> </element>
  <element />
</root>

Gesamtes Dokument:

declare @X xml =
'<root xml:space = "preserve">
  <element> </element>
  <element> </element>
</root>'

select @X;

Ergebnis:

<root xml:space="preserve">
  <element> </element>
  <element> </element>
</root>

Eine weitere Option für das gesamte Dokument ist die Verwendung der Konvertierung mit Stil 1 .

Bewahren Sie unbedeutenden Leerraum. Diese Stileinstellung legt die standardmäßige Behandlung von xml: space so fest, dass sie dem Verhalten von xml: space = "preserve" entspricht.

declare @X xml = convert(xml, 
'<root>
  <element> </element>
  <element> </element>
</root>', 1)

select @X;
Mikael Eriksson
quelle
Interessant, dass dies erforderlich ist. Es sollte nicht die Aufgabe von SQL Server sein, zu entscheiden, welches Leerzeichen "unbedeutend" ist, und es ohne Änderung des Dokuments stillschweigend zu entfernen!
Leichtigkeit Rennen mit Monica
3
@LightnessRacesinOrbit Ich bin sehr zufrieden mit der Implementierung von SQL Server. Die Formatierung (Whitespace) in XML wird erst dann als wichtig erachtet, wenn Sie dies angeben. Schauen Sie sich dieses Beispiel an, um die Anzahl der Knoten im Dokument und die Auswirkungen auf die Speichergröße zu sehen.
Mikael Eriksson,
3
Ich halte es für einen Verstoß gegen die Spezifikation, da hier die Daten als XML akzeptiert und als XML gespeichert werden, ohne Manipulation oder Transformation oder irgendeine andere Form von XML-Ebenen-Spielereien außer dem einfachen Speichern des Dokuments (angeblich), so wie es das Verhalten sollte fallen eher in die eines "Prozessors" als in eine "Anwendung" und dürfen daher keine Whitespaces entfernen .
Leichtigkeit Rennen mit Monica
9

Auf dieser Seite der SQL Server-Dokumentation heißt es

Die Daten werden in einer internen Darstellung gespeichert, bei der es sich möglicherweise nicht um eine identische Kopie des XML-Texts handelt, da die folgenden Informationen nicht beibehalten werden: unbedeutende Leerzeichen, Reihenfolge der Attribute, Namespace-Präfixe und XML-Deklaration.

Ich nehme an, für Ihr Beispiel ist der Leerraum des mittleren Tags nicht signifikant und es steht daher frei, die Darstellung umzugestalten. Ich glaube nicht, dass es dafür eine Lösung gibt. Es ist nur, wie SQL Server den XML-Datentyp implementiert.

Workarounds würden die Verwendung eines Platzhalters anstelle von Leerzeichen beinhalten, wie @Aaron sagt. Der Verbraucher muss daran denken, diese Token einzulegen und abzustreifen. Alternativ können Sie die Spalte als nvarchar anstelle von XML definieren. Dadurch bleiben auf jeden Fall alle Leerzeichen und andere Formatierungen erhalten. Ein kurzes Beispiel:

create table x(i nvarchar(99), j xml);
insert x values ('<a> </a>', '<a> </a>');  -- note the space
select * from x

i           j
----------  -------
<a> </a>    <a />  

Die nvarchar-Spalte behält das Eingabeformat bei, die XML-Spalte nicht.

Sie verlieren die Möglichkeit, XPATH in SQL-Abfragen zu verwenden. Wenn das XML nur in der Anwendung geschreddert wird, spielt dies keine Rolle. Außerdem kann die Zeichenfolge komprimiert werden, um Platz in der Datenbank zu sparen, wenn dies für Sie von Bedeutung ist.

Michael Green
quelle
Sie könnten XPATH wahrscheinlich immer noch in Abfragen gegen die XML-Version verwenden, auch wenn Sie sie nur neu formatieren lassen, solange Sie sich nicht auf einen Treffer (oder Fehler) für den unbedeutenden Speicherplatz dort verlassen.
Aaron Bertrand
0

Sie könnten Ihren Platz CDATAbeim Speichern der Daten einschließen:

<xsl:text><![CDATA[ ]]></xsl:text>

Es scheint, dass SQL Server den Speicherplatz dann intern behält, aber das unnötige CDATAMarkup selbst entfernt, wenn das Ergebnis wieder verwendet wird SELECT. Glücklicherweise bleibt der Platz erhalten, wenn das Ergebnis von Folgendem wiederverwendet wird SELECT:

DECLARE @X XML = '<text><![CDATA[ ]]></text>'
DECLARE @Y XML

SET @Y = (SELECT @X)

SELECT @Y

Das Ergebnis wird sein:

<text> </text>
Bruno
quelle
Auch versucht, CDATA, aber es wurde auch entfernt.
Herr Zach
@MrZach CDATA selbst wird entfernt, der Speicherplatz bleibt jedoch erhalten. (Versucht mit SQL Express 2016.)
Bruno
Seltsam, hier wurde der Raum entfernt. Denken Sie auch Express 2016 oder 2017
Herr Zach