我有一个关于替换XML列的问题,这是一个关于我想要改变的小例子。
<i><recipes n="0" />
<CGrecipes cg="4" r0="302053" r1="302084" r2="302049" r3="302068" />
<HArecipes ha="4" r0="302103" r1="302083" r2="302050" r3="302087" />
<KHrecipes kh="10" r0="302100" r1="302090" r2="302078" r3="302074"
r4="302094" r5="302082" r6="302066" r7="302051"
r8="302086" r9="302070" />
<KHNrecipes khn="10" r0="302102" r1="302089" r2="302056" r3="302077"
r4="302052" r5="302069" r6="302081" r7="302073"
r8="302093" r9="302085" />
<IMITARrecipes imitar="2" r0="302110" r1="302057" />
<MAUSERrecipes mauser="1" r0="302106" />
<SVDrecipes svd="1" r0="302059" />
<BLASERrecipes blaser="2" r0="302105" r1="302060" />
<SIGSAUERrecipes sigsauer="2" r0="302109" r1="302061" />
<HONEYBADGERrecipes honeybadger="1" r0="302062" />
<SMALLBACKPACKrecipes smallbackpack="1" r0="302095" />
<MEDIUMBACKPACKrecipes mediumbackpack="1" r0="302096" />
<MILITARYBACKPACKrecipes militarybackpack="1" r0="302097" />
<LARGEBACKPACKrecipes largebackpack="1" r0="302098" />
<TEDDYBACKPACKrecipes teddybackpack="1" r0="302099" />
<ALICEBACKPACKrecipes alicebackpack="1" r0="302112" />
<M82recipes m82="1" r0="302107" />
<AWMrecipes awm="1" r0="302108" />
<B93Rrecipes b93r="1" r0="302111" />
</i>
我想用脚本更改它:
<i><recipes r="0" r0="302053" r1="302084" r2="302049" r3="302068" r4="302103" r5="302083" r6="302050" r7="302087" r8="302100" r9="302090" r10="302078" r11="302074" r12="302094" r13="302082" r14="302066" r15="302051" r16="302086" r17="302070" r18="302102" r19="302089" r20="302056" r21="302077" r22="302052" r23="302069" r24="302081" r25="302073" r26="302093" r27="302085" r28="302110" r29="302057" r30="302106" r31="302059" r32="302105" r33="302060" r34="302109" r35="302061" r36="302062" r37="302095" r38="302096" r39="302097" r40="302098" r41="302099" r42="302112" r43="302107" r44="302108" r45="302111" /></i>
我想得到帮助和建议!
答案 0 :(得分:1)
嗯,这可能不是更简单(字面意思,我认为),这要归功于T-SQL非常有限的XQuery实现,以及对任何类型的动态XML的普遍仇恨。让@xml
在变量中包含您的XML(如果它是一列,请根据需要添加FROM
。)
SELECT CONVERT(XML, REPLACE((
SELECT @xml.value('/i[1]/recipes[1]/@n', 'int') AS [@r], '' AS [@marker]
FOR XML PATH('recipes'), ROOT('i')
), 'marker=""', (
SELECT ' ' + REPLACE(REPLACE('r#="$v"',
'#', ROW_NUMBER() OVER (ORDER BY (SELECT 1)) - 1),
'$v', t.value('text()[1]', 'int'))
FROM (
SELECT @xml.query('
for $a in //*/@*[substring(local-name(),1,1)="r"]
return <r>{string($a)}</r>
') AS a
) _ CROSS APPLY a.nodes('r') AS x(t)
FOR XML PATH('')
)))
从内部到外部:我们将所有r*
属性解包到元素中,将行号附加到它们,然后通过连接字符串将结果折叠回XML。对于结局,我们将n
的{{1}}属性转换为recipes
,并将字符串连接替换为外部元素。
为什么这段代码太可怕了?因为数据模型很糟糕(好吧,因为SQL Server的XQuery实现非常有限,省略了可以简化这一过程的大多数高级功能)。它在各方面都滥用XML。考虑将属性更改为子元素。不要使用r
之类的连接元素名称,将其概括为ALICEBACKPACKrecipes
或类似名称。想想静态名称和重复内容:
recipes name='ALICEBACKPACK'
对于任何不是完全成熟的编程语言的东西,查询和处理起来要容易得多。