2009-09-15 18 views
6

¿Hay alguna manera de tener un SQL Server SQL return use CDATA? He XML de ser devuelto por SQL Server como esto:SQL Server XML output with CDATA

<locations> 
    <site id="124"> 
     <sitename>Texas A &amp; M</sitename> 
    </site> 
</locations> 

Cuando estoy obligado a tener presente:

<locations> 
    <site id="124"> 
     <sitename><![CDATA[Texas A & M]]></sitename> 
    </site> 
</locations> 
+3

Parece un requisito extraño: ambos deberían pasar a ser lo mismo en cualquier par de xml compatible con los estándares er. Pero luego, los clientes serán clientes. –

+0

Desafortunadamente, el proceso posterior no es una opción, ya que SQL ya tomó datos de columna (Texas A & M) y escapó para XML (Texas A & M) directo. Algo que CDATA permite. El cliente no desea analizar el XML, luego buscar y reescribir los valores. Y rápidamente descubrí que devolver XML, en lugar de tomar una consulta de retorno y construir la cadena XML a mano, es la preferencia definitiva. –

Respuesta

14

Mire las opciones de FOR XML EXPLICIT (parámetro Directiva). Le da un mayor grado de control y también puede especificar CDATA. Aquí está a good tutorial.

Y el código addapted de ese tutorial:

declare @agent table 
( 
    AgentID int, 
    Fname varchar(5), 
    SSN varchar(11) 
) 

insert into @agent 
select 1, 'Vimal', '123-23-4521' union all 
select 2, 'Jacob', '321-52-4562' union all 
select 3, 'Tom', '252-52-4563' 

SELECT 
    1 AS Tag, 
    NULL AS Parent, 
    NULL AS 'Agents!1!', 
    NULL AS 'Agent!2!AgentID', 
    NULL AS 'Agent!2!Fname!Element', 
    NULL AS 'Agent!2!SSN!cdata' 
UNION ALL 
SELECT 
    2 AS Tag, 
    1 AS Parent, 
    NULL, 
    AgentID, 
    Fname, 
    SSN 
FROM @agent 
FOR XML EXPLICIT 
+0

Esto estaba justo en el dinero. Gracias por la ayuda. –

+1

Tenga en cuenta, sin embargo, que si inserta esta salida en una variable XML de T-SQL o en un campo XML, el CDATA se convertirá de nuevo al formato de escalas ampersand y no se podrá desactivar. http://stackoverflow.com/a/9133622/864696 –

0

Como Joel menciona en el comentario anterior, esas dos formas debe significar exactamente lo mismo . Sin embargo, si realmente se requiere el formulario CDATA, entonces podría escribir un post-procesador que tome el primer formulario como entrada y entregue el segundo formulario usando CDATA.

Al hacer esto, un post-procesador haría descodifica los datos XML-escapado en la primera forma, y ​​volver a codificar utilizando un método compatible con CDATA. Consulte la pregunta Is there a way to escape a CDATA end token in xml? para consideraciones sobre el escape de CDATA.

0

Aquí es un ejemplo de mi manera de conseguir CDATA:

DECLARE @GlobalDateFormat varchar(32) 
SET @GlobalDateFormat = 'MM/dd/yyyy hh:mm tt' 

DECLARE @xml XML 

SET @xml = 
(
    SELECT 
      SegmentId   = ISNULL(SegmentId,0) 
     , DocumentId  = ISNULL(DocumentId,0) 
     , Title    = CAST(Core.dbo.fCharFormat('xmlCDATA',Title,DEFAULT,'') AS xml) 
     , DocumentShortName = CAST(Core.dbo.fCharFormat('xmlCDATA',DocumentShortName,DEFAULT,'') AS xml) 
     , [FileName]  = CAST(Core.dbo.fCharFormat('xmlCDATA',[FileName],DEFAULT,'') AS xml) 
     , [Path]   = CAST(Core.dbo.fCharFormat('xmlCDATA',[Path],DEFAULT,'') AS xml) 
     , CreateDate  = ISNULL(Core.dbo.fDateFormat(@GlobalDateFormat,CreateDate),Core.dbo.fDateFormat(@GlobalDateFormat,GETDATE())) 
     , ModificationDate = ISNULL(Core.dbo.fDateFormat(@GlobalDateFormat,ModificationDate),Core.dbo.fDateFormat(@GlobalDateFormat,GETDATE())) 
     , TemplateId  = ISNULL(CAST(TemplateId AS varchar(16)),'') 
     , IsRoot   = ISNULL(IsRoot,0) 
     , IsActive   = ISNULL(IsActive,0) 
     , SortOrdinal  = ISNULL(CAST(SortOrdinal AS varchar(16)),'') 
     , ClientId   = ISNULL(ClientId,'') 
     , Tag    = CAST(Core.dbo.fCharFormat('xmlCDATA',Tag,DEFAULT,'') AS xml) 
     FROM 
      Document 
     WHERE 
      DocumentId = 9073 
     FOR XML AUTO, ELEMENTS 
) 

SELECT @xml 

Ahí está el detalle relevante de mi comadreja, CDATA- función de manejo:

IF @cmdName = 'xmlCDATA' 
BEGIN 
    IF @chars IS NULL 
    BEGIN 
     SET @charsOut = @charsDefault 
    END 
    ELSE 
    BEGIN 
     SET @chars = REPLACE(@chars,'<![CDATA[','') 
     SET @chars = REPLACE(@chars,']]>','') 
     SET @charsOut = '<![CDATA[' + @chars + ']]>' 
    END 
END 
+0

Esto fallará si alguno de sus datos, ej. Título, contiene la cadena ']]>'. –

+0

¡Ay! ¡Derecha! Voy a tener que escribir una función dedicada exclusivamente a CDATA ... debería tenerlo al final del día ... – rasx

+0

Espera un momento 'Greg, acabo de probar esto en Management Studio: SELECT CAST (' 'AS xml) ¿Has probado esto? ¿Lo que pasa? – rasx