【问题标题】:Get a text field formated as xml body value获取格式为 xml 正文值的文本字段
【发布时间】:2019-08-08 11:35:38
【问题描述】:

我有一个表格,其中一列以 xml 格式存储,因此可以在其他项目中使用格式化文本显示它。

但我需要将其转换为没有标签的单行。

我尝试过使用 value() 方法和 nodes(),但没能成功...

这是我要格式化的列的内容示例。

<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml">    <head>      <title></title>      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />      <style type="text/css">p {font-family: sans-serif;font-size: 8.25pt;margin: 0px;}</style>    </head>    <body>      <p>VALUE I WANT TO GET </p>    </body>  </html>
SELECT Id, Description, Value FROM MyTable

Value 是存储 xml 的列。

有没有办法在一行中获取没有任何标签的正文内容?

列不是 XML 类型,而是 VARCHAR(MAX) 类型

【问题讨论】:

    标签: sql sql-server xml vb.net


    【解决方案1】:

    如果您的 HTML 值总是相同的格式,请尝试以下脚本一起使用:

    1. 将 HTML 转换为支持的格式以使用 value ()node() 进行查询
        Declare @x nvarchar (4000) = '<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml">    <head>      <title></title>      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />      <style type="text/css">p {font-family: sans-serif;font-size: 8.25pt;margin: 0px;}</style>    </head>    <body>      <p>VALUE I WANT TO GET </p>    </body>  </html>'
    
        select @x = replace (@x, 
                                '<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> ',
                                ''
                            );
    
        SELECT @x = REPLACE(@x, 'xmlns=', 'xmlns:i=');
    
        --Print @x;
    
    1. 转换后的 XML 的实际选择查询
        select  xmldata, 
                Cast (x2.c.query('data(body/p)') as nvarchar (100)) as HtmlBody
        From
            (select convert (xml, @x ) as xmldata) as x
                cross apply xmldata.nodes('html') as x2(c)
    

    补充:
    查询直接表,如果您将@temp相应地替换为您的表名和列名,希望这会起作用

    
    Declare @Temp table (ID bigint, xmlvalue nvarchar(4000) );
    Declare @x nvarchar (4000) = '<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml">    <head>      <title></title>      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />      <style type="text/css">p {font-family: sans-serif;font-size: 8.25pt;margin: 0px;}</style>    </head>    <body>      <p>VALUE I WANT TO GET </p>    </body>  </html>';
    
    Insert into @Temp 
    VALUES (101, @x);
    
    
    select  x.*, 
            Cast (x2.c.query('data(body/p)') as nvarchar (100)) as HtmlBody
    From    (
            select ID, CAST(REPLACE(
                            (replace (xmlvalue, 
                                    '<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> ',
                                    '') ),
                            'xmlns=', 
                            'xmlns:i='
                            ) AS xml) as xmldata
            from @Temp
            ) as x
            CROSS APPLY xmldata.nodes('html') as x2(c)
    go
    
    

    如果您认为将来难以管理,请创建具有相同逻辑的标量函数 - 使用 custom scalar functions 时考虑性能方面的建议

    【讨论】:

    • 除此之外,这可以更简单地实现,我觉得有必要根据提示编写创建具有相同逻辑的标量函数。标量函数几乎在任何情况下表现都非常糟糕,应该避免......
    • ... 并转换结果。 query() 到 nvarchar 不会解析实体...您必须使用。值()...
    • 感谢您的通知,如果您能分享一些测试用例或进一步的解释,这对我们非常有用。
    • 我自己已经给出了答案。你检查了吗?
    【解决方案2】:

    你可以做类似这样的事情: 语言是VB.Net。

    Dim XMLDoc As New XmlDocument
    Dim dt As DataTable = GetData()  <-- GetData() is where you load the data using your query
    
    XMLDoc.Load(dt.Rows(0).Item("Value").ToString)
    
    Dim TextThatIWant As string = XMLDoc.SelectSingleNode("/html/body/p").InnerText
    

    【讨论】:

      【解决方案3】:

      试试这样:

      DECLARE @YourValue VARCHAR(MAX)=
      '<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml">    <head>      <title></title>      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />      <style type="text/css">p {font-family: sans-serif;font-size: 8.25pt;margin: 0px;}</style>    </head>    <body>      <p>VALUE I WANT TO GET </p>    </body>  </html>';
      
      WITH XMLNAMESPACES(DEFAULT 'http://www.w3.org/1999/xhtml')
      SELECT CONVERT(xml,@YourValue,2).value('(/html/body/p/text())[1]','varchar(1000)');
      

      简而言之:

      • 由于&lt;!DOCTYPE&gt;,我们不能将CAST() 字符串转换为XML,但我们可以使用CONVERT() 和参数2。这会将您的字符串作为 XML 返回。
      • 针对XML我们可以使用.value()
      • 当您的 XML 声明 默认命名空间时,我们使用 WITH XMLNAMESPACES 声明此命名空间

      注意:HTML 远没有 XML 严格。如果您不能确定您的 HTML 实际上是 XHTML(这意味着它遵循更严格的 XML 规则),那么依赖 XML 方法可能会很危险。幸运的是,命名空间指向 xhtml...
      如果没有,这可能适用于您的所有测试,但随时会中断生产...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-01-04
        • 1970-01-01
        • 2011-05-30
        • 2015-08-26
        • 2018-09-10
        • 2011-08-02
        • 1970-01-01
        相关资源
        最近更新 更多