简体   繁体   中英

Manipulating the xml column in sql server using Xquery

I am storing an xml file in the xml datatype in table of SQL Server. Now I want to fetch some fragments (using xquery) and then update the fragments with the modified fragments (using xquery). I need some suggestions.

I have the code to delete a node and it is as below but while deleting I need to insert the modified node at the same place. How can this be done?

--SET @doc.modify('delete (/DATA/SDACTS)')

This works if I want to delete a node but what about inserting the modified node at same location

Next I want to delete the nodes whose values will be passed as querystring so I have to build up the string

like below

DECLARE @x XML 

SET @x = '
<DATA>
  <SDACTS>
    <SDACT TYPE="Economy" COLOUR="0xff0000" />
    <SDACT TYPE="Environment" COLOUR="0x00ff00" />
    <SDACT TYPE="People" COLOUR="0x0000ff" />
    <SDACT TYPE="Society" COLOUR="0xff00ff" />
  </SDACTS>
<LOCATIONS>
    <CONTINENT TITLE="South America">
      <COUNTRY TITLE="Chile">
        <HEADOFFICE>Santiago</HEADOFFICE>
        <ADDRESS>
          &lt;p&gt;Pedro de Valdivia 291&lt;/p&gt;&lt;p&gt;Providencia&lt;/p&gt;&lt;p&gt;Santiago&lt;/p&gt;
        </ADDRESS>
        <LATITUDE>-33.426127</LATITUDE>
        <LONGITUDE>-70.611469</LONGITUDE>
        <BUSINESSUNITS>Copper</BUSINESSUNITS>        
        <EMPLOYEES />
        <NUMBEROFBUSINESS>1</NUMBEROFBUSINESS>
      </COUNTRY>
      <COUNTRY TITLE="Brazil">
        <HEADOFFICE>Brazil</HEADOFFICE>
        <ADDRESS>
          &lt;p&gt;Pedro de Valdivia 291&lt;/p&gt;&lt;p&gt;Providencia&lt;/p&gt;&lt;p&gt;Santiago&lt;/p&gt;
        </ADDRESS>
        <LATITUDE>-38.426127</LATITUDE>
        <LONGITUDE>-60.611469</LONGITUDE>
        <BUSINESSUNITS>Zinc</BUSINESSUNITS>        
        <EMPLOYEES />
        <NUMBEROFBUSINESS>2</NUMBEROFBUSINESS>
      </COUNTRY>
    </CONTINENT>
</LOCATIONS>
</DATA>

I have to delete the country brazil which lies in the continent South America so I have to keep these as parameters which has to be dynamic as other country and continent can come.

declare @country varchar(50)
declare @continent  varchar(50)
set @country = 'Brazil'
set @continent = 'South America'

declare @final varchar(100)
set @final = '//CONTINENT[@TITLE="' + @continent + '"]/COUNTRY[@TITLE="' + @country + '"]'
select @final
--SELECT @doc.query('sql:variable("@final")') 'XmlDesc'  This works for select statement but not for delete
SET @doc.modify('delete (sql:variable("@final"))')   This does not work and gives error.
 SELECT @doc

My requirement:

Basically I am making a xml editing tool in .NET and jQuery tree hangs when loading huge xml files so I am storing the huge xml file in table and calling the segments (child nodes) and then loading those segments in jquery tree and user modifies those node. I take the modified segments to the database and then want to update with the modified one.

Edit 2 : It looks like SLQ-Server is not a fully complaint XQuery processor...

So, a more "static" XQuery (wich is fine is the schema is well known):

declare variable $continent external;
declare variable $country external;
declare variable $xml as item() external;
element DATA {
   /DATA/@*,
   /DATA/*[not(self::LOCATIONS)],
   element LOCATIONS {
      /DATA/LOCATIONS/@*,
      for $cont in /DATA/LOCATIONS/CONTINENT
      return element CONTINENT {
                $cont/@*,
                for $count in $cont/COUNTRY
                return if ($cont/@TITLE=$continent and
                           $count/@TITLE=$country)
                       then $xml
                       else $count
             }
   }
}

With this parameters (With SQL-Server you could also use sql:variable() extension function):

continent="'South America'"
country="'Brazil'"
xml="<COUNTRY TITLE='Brazil'><UPDATE/></COUNTRY>"

Output:

<DATA>
    <SDACTS>
        <SDACT TYPE="Economy" COLOUR="0xff0000"/>
        <SDACT TYPE="Environment" COLOUR="0x00ff00"/>
        <SDACT TYPE="People" COLOUR="0x0000ff"/>
        <SDACT TYPE="Society" COLOUR="0xff00ff"/>
    </SDACTS>
    <LOCATIONS>
        <CONTINENT TITLE="South America">
            <COUNTRY TITLE="Chile">
                <HEADOFFICE>Santiago</HEADOFFICE>
                <ADDRESS>
          &lt;p&gt;Pedro de Valdivia 291&lt;/p&gt;&lt;p&gt;Providencia&lt;/p&gt;&lt;p&gt;Santiago&lt;/p&gt;
                </ADDRESS>
                <LATITUDE>-33.426127</LATITUDE>
                <LONGITUDE>-70.611469</LONGITUDE>
                <BUSINESSUNITS>Copper</BUSINESSUNITS>
                <EMPLOYEES/>
                <NUMBEROFBUSINESS>1</NUMBEROFBUSINESS>
            </COUNTRY>
            <COUNTRY TITLE="Brazil">
                <UPDATE/>
            </COUNTRY>
        </CONTINENT>
    </LOCATIONS>
</DATA>

EDIT 3 : I think that the correct syntax for your query in comments is:

declare @continent varchar(100) 
declare @country varchar(100) 
declare @xml xml 
declare @count int 
declare @doc xml 
set @continent='South America' 
set @country='Brazil' 
set @xml='<COUNTRY TITLE="Brazil"><UPDATE/></COUNTRY>' 
set @count = 1 
select @doc = xmldesc from varunxmlanglo where idlanguage =1 and xmltype ='D' 
select @doc.query('
element DATA {
   /DATA/@*,
   /DATA/*[not(self::LOCATIONS)],
   element LOCATIONS {
      /DATA/LOCATIONS/@*,
      for $continent in /DATA/LOCATIONS/CONTINENT
      return element CONTINENT {
                $continent/@*,
                for $country in $continent/COUNTRY
                return if ($continent/@TITLE=sql:variable("@continent") and                                                       $country/@TITLE=sql:variable("@country"))
                       then sql:variable("@xml")
                       else $country
             }
   }
}
')

Note : In XQuery variable reference have $ prefixed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM