如何在Tally XML字符串中区分两个节点及其子节点

时间:2019-04-23 08:01:23

标签: sql sql-server xml tsql tally

我的XML是这样的:

<ENVELOPE>
    <DSPACCNAME>
        <DSPDISPNAME>Opening Stock</DSPDISPNAME>
    </DSPACCNAME>
    <PLAMT>
        <PLSUBAMT/>
        <BSMAINAMT>-44912711.35</BSMAINAMT>
    </PLAMT>
    <BSNAME>
        <DSPACCNAME>
            <DSPDISPNAME>Stock-in-Hand-Accesories(KPM)</DSPDISPNAME>
        </DSPACCNAME>
    </BSNAME>
    <BSAMT>
        <BSSUBAMT>-15750.01</BSSUBAMT>
        <BSMAINAMT/>
    </BSAMT>
    <BSNAME>
        <DSPACCNAME>
            <DSPDISPNAME>Stock-in-Hand-Accesories(KVM)</DSPDISPNAME>
        </DSPACCNAME>
    </BSNAME>
    <BSAMT>
        <BSSUBAMT>-16750.01</BSSUBAMT>
        <BSMAINAMT/>
    </BSAMT>
    <DSPACCNAME>
        <DSPDISPNAME>Closing Stock</DSPDISPNAME>
    </DSPACCNAME>
    <BSNAME>
        <DSPACCNAME>
            <DSPDISPNAME>Stock-in-Hand-Accesories(KPM)</DSPDISPNAME>
        </DSPACCNAME>
    </BSNAME>
    <BSAMT>
        <BSSUBAMT>-54750.01</BSSUBAMT>
        <BSMAINAMT/>
    </BSAMT>
    <BSNAME>
        <DSPACCNAME>
            <DSPDISPNAME>Stock-in-Hand-Accesories(KRM)</DSPDISPNAME>
        </DSPACCNAME>
    </BSNAME>
    <BSAMT>
        <BSSUBAMT>-74750.01</BSSUBAMT>
        <BSMAINAMT/>
    </BSAMT>
</ENVELOPE>

我的结果应该是:

Opening Stock   Stock-in-Hand-Accesories(KPM)   -15750.01
Opening Stock   Stock-in-Hand-Accesories(KVM)   -16750.01
Closing Stock   Stock-in-Hand-Accesories(KPM)   -54750.01
Closing Stock   Stock-in-Hand-Accesories(KRM)   -74750.01

2 个答案:

答案 0 :(得分:2)

假设唯一的关系是节点的顺序,则可以选择所有BSNAME个节点作为锚点,并使用>><<运算符查找最接近的BSAMTDSPACCNAME个节点:

DECLARE @xml XML = '<ENVELOPE>
    <DSPACCNAME>
        <DSPDISPNAME>Opening Stock</DSPDISPNAME>
    </DSPACCNAME>
    <PLAMT>
        <PLSUBAMT/>
        <BSMAINAMT>-44912711.35</BSMAINAMT>
    </PLAMT>
    <BSNAME>
        <DSPACCNAME>
            <DSPDISPNAME>Stock-in-Hand-Accesories(KPM)</DSPDISPNAME>
        </DSPACCNAME>
    </BSNAME>
    <BSAMT>
        <BSSUBAMT>-15750.01</BSSUBAMT>
        <BSMAINAMT/>
    </BSAMT>
    <BSNAME>
        <DSPACCNAME>
            <DSPDISPNAME>Stock-in-Hand-Accesories(KVM)</DSPDISPNAME>
        </DSPACCNAME>
    </BSNAME>
    <BSAMT>
        <BSSUBAMT>-16750.01</BSSUBAMT>
        <BSMAINAMT/>
    </BSAMT>
    <DSPACCNAME>
        <DSPDISPNAME>Closing Stock</DSPDISPNAME>
    </DSPACCNAME>
    <BSNAME>
        <DSPACCNAME>
            <DSPDISPNAME>Stock-in-Hand-Accesories(KPM)</DSPDISPNAME>
        </DSPACCNAME>
    </BSNAME>
    <BSAMT>
        <BSSUBAMT>-54750.01</BSSUBAMT>
        <BSMAINAMT/>
    </BSAMT>
    <BSNAME>
        <DSPACCNAME>
            <DSPDISPNAME>Stock-in-Hand-Accesories(KRM)</DSPDISPNAME>
        </DSPACCNAME>
    </BSNAME>
    <BSAMT>
        <BSSUBAMT>-74750.01</BSSUBAMT>
        <BSMAINAMT/>
    </BSAMT>
</ENVELOPE>';
SELECT refnode.value('(./DSPACCNAME/DSPDISPNAME)[1]', 'VARCHAR(100)') AS [BSNAME]
     , refnode.value('let $c := . return (../BSAMT[. >> $c]/BSSUBAMT)[1]', 'DECIMAL(18,2)') AS [BSAMT]
     , refnode.value('let $c := . return (../DSPACCNAME[. << $c]/DSPDISPNAME)[last()]', 'VARCHAR(100)') AS [DSPACCNAME]
FROM @xml.nodes('//ENVELOPE/BSNAME') x(refnode)

Demo on db<>fiddle

答案 1 :(得分:0)

尽管可以按Salman A的建议进行操作,但它很容易出错。看起来此XML是由自定义TDL(Tally附加组件)组成的。在这种情况下,我同意Panagiotis Kanavos的观点,即XML格式不正确。您可以让TDL开发人员简单地重新排列XML标签,方法是将XML标签放置在每个父节点的“行”级别,并将每个子节点放置在“字段”级。请注意,必须使用'Repeat'变量来重复行,以使多个带有子节点的父节点出现在XML中。

您可以参考reference guide,特别是有关如何使用XML标签的第2.2.5节。