XPath 1.0 to find if an element's value is in a list of values

后端 未结 2 1162
广开言路
广开言路 2020-12-03 02:29

Is there a way to construct an XPath that evaluates whether an element\'s value is in a predefined list of values? Something akin to this:

/Location/Addr[Sta         


        
2条回答
  •  醉梦人生
    2020-12-03 03:13

    Just necromancing, since XPath 2.0 has come along.

    With XPath 2.0, you can do:

    /Location/Addr[State=('TX', 'AL', 'MA')]
    

    Alternatively, with XPath 1.0, you can use contains in combination with string-length:

    DECLARE @tXML xml = '
    
    
    tt
    
    
    
    ';
    
    -- SELECT @tXML;
    
    SELECT 
        c.p.value('(@data-objid)[1]', 'varchar(50)') AS objID 
    FROM @tXML.nodes('//node()[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]') AS c(p)
    
    
    SET @tXML.modify('delete //node()[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]'); 
    
    SELECT @tXML AS del;
    
    DECLARE @newRecord xml = ''; 
    
    
    -- SET @tXML.modify('insert sql:variable("@newRecord") as first into (/svg/g)[1]')
    SET @tXML.modify('insert sql:variable("@newRecord") as last into (/svg/g)[1]')
    
    SELECT @tXML AS ins;
    

    See also: add block into specific position

    And to update (with xml, you can only update one value at a time, and the text()selector finds nothing for an empty element, so you first need to empty the element, then insert the value, and that for each match):

    SET @tXML.modify('replace value of (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]/text())[1] with "40"')
    SET @tXML.modify('replace value of (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]/text())[2] with "40"')
    
    SET @tXML.modify('replace value of (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]/text())[1] with ""')
    SET @tXML.modify('insert text{"This Works"} into (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0])[1]')
    
    SET @tXML.modify('replace value of (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]/text())[2] with ""')
    SET @tXML.modify('insert text{"This Works"} into (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0])[2]')
    

    And to insert and delete an attribute

    -- insert attribute
    -- SET @tXML.modify('insert attribute data-objid1 {"1"} into (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0])[1]')
    -- delete attribute
    -- and then, delete suddenly can remove several nodes - unlike insert or modify ... 
    -- SET @tXML.modify('delete (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0])/@data-objid[1]')
    
    -- only insert if there is no attribute "data-objid", therefore check with [not(@data-objid)]
    -- (on replace, it doesn't create an attribute if it doesn't exist)
    SET @tXML.modify('insert attribute data-objid {"1"} into (//path[not(@data-objid) and contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0])[1]')
    SET @tXML.modify('replace value of (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]/@data-objid)[1] with "Test"')
    

    And with variables:

    DECLARE @testvar varchar(30); 
    SET @testvar = 'abc'; 
    SET @tXML.modify('insert attribute data-objid {sql:variable("@testvar")} into (//path[not(@data-objid)] and contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0)[1]')
    SET @tXML.modify('replace value of (//path[contains("0000X1,0000X2", @data-objid) and string-length(@data-objid) != 0]/@data-objid)[1] with sql:variable("@testvar")')
    SET @testvar = '0000X1,0000X2'; 
    SET @tXML.modify('delete (//path[contains(sql:variable("@testvar"), @data-objid) and string-length(@data-objid) != 0])/@data-objid[1]')
    

    Note that you should concat the attribute data-objid to ("," + objid + ","), so that modify doesn't accidentally find it if the testvar is ',0000X1a,0000X2b,' instead of ',0000X1,0000X2,' (for example)

    DECLARE @testvar varchar(30); 
    SET @testvar = ',0000X1a,0000X2b,'; 
    SET @tXML.modify('delete (//path[contains(sql:variable("@testvar"), concat(",", @data-objid, ",")) and string-length(@data-objid) != 0])/@data-objid[1]')
    
    SELECT @tXML 
    

提交回复
热议问题