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

How to differentiate two nodes with their childs in a Tally XML string

我有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

假设唯一的关系是节点的顺序,你可以select所有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

虽然这可以按照 Salman A 的建议进行,但很容易出错。看起来这个 XML 是由自定义 TDL(Tally 插件)组成的。在这种情况下,我同意 Panagiotis Kanavos 的观点,即 XML 的格式不正确。您可以让 TDL 开发人员简单地重新安排 XML 标签,方法是在每个父节点的 'Line' 级别放置一个 XML 标签,并在每个父节点的 'Field' 级别放置一个 XML 标签子节点。请注意,对于具有子节点的多个父节点,必须使用 'Repeat' 变量重复该行才能出现在 XML.

您可以参考此 reference guide,特别是第 2.2.5 节,了解如何使用 XML 标签。