【发布时间】:2017-01-13 15:23:46
【问题描述】:
首先,我知道SO question 有点不同。
我有一个如下所示的 XML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
<CstmrCdtTrfInitn>
<GrpHdr>
<MsgId>123</MsgId>
<CreDtTm>321</CreDtTm>
<NbOfTxs>10</NbOfTxs>
<CtrlSum>18700.68</CtrlSum>
<InitgPty>
<Nm>some info</Nm>
</InitgPty>
</GrpHdr>
<PmtInf>
<!-- start -->
<PmtInfId>asd</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<BtchBookg>false</BtchBookg>
<PmtTpInf>
<InstrPrty>NORM</InstrPrty>
<SvcLvl>
<Prtry>test</Prtry>
</SvcLvl>
</PmtTpInf>
<ReqdExctnDt>date</ReqdExctnDt>
<Dbtr>
<Nm>something</Nm>
<PstlAdr>
<AdrLine>addr 1</AdrLine>
</PstlAdr>
</Dbtr>
<!-- end -->
<CdtTrfTxInf>
<PmtId>
<InstrId>16082672122</InstrId>
<EndToEndId>16082672122</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="RON">2159.41</InstdAmt>
</Amt>
<CdtrAgt>
<FinInstnId>
<BIC>some bic</BIC>
</FinInstnId>
</CdtrAgt>
</CdtTrfTxInf>
</PmtInf>
<PmtInf>
<!-- start -->
<PmtInfId>asd</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<BtchBookg>false</BtchBookg>
<PmtTpInf>
<InstrPrty>NORM</InstrPrty>
<SvcLvl>
<Prtry>test</Prtry>
</SvcLvl>
</PmtTpInf>
<ReqdExctnDt>date</ReqdExctnDt>
<Dbtr>
<Nm>something</Nm>
<PstlAdr>
<AdrLine>addr 1</AdrLine>
</PstlAdr>
</Dbtr>
<!-- end -->
<CdtTrfTxInf>
<PmtId>
<InstrId>16082672122</InstrId>
<EndToEndId>16082672122</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="RON">2159.41</InstdAmt>
</Amt>
<CdtrAgt>
<FinInstnId>
<BIC>some bic</BIC>
</FinInstnId>
</CdtrAgt>
</CdtTrfTxInf>
</PmtInf>
<PmtInf>
<!-- start -->
<PmtInfId>asd</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<BtchBookg>false</BtchBookg>
<PmtTpInf>
<InstrPrty>NORM</InstrPrty>
<SvcLvl>
<Prtry>test</Prtry>
</SvcLvl>
</PmtTpInf>
<ReqdExctnDt>date</ReqdExctnDt>
<Dbtr>
<Nm>something</Nm>
<PstlAdr>
<AdrLine>addr 1</AdrLine>
</PstlAdr>
</Dbtr>
<!-- end -->
<CdtTrfTxInf>
<PmtId>
<InstrId>16082672122</InstrId>
<EndToEndId>16082672122</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="RON">2159.41</InstdAmt>
</Amt>
<CdtrAgt>
<FinInstnId>
<BIC>some bic</BIC>
</FinInstnId>
</CdtrAgt>
</CdtTrfTxInf>
</PmtInf>
<PmtInf>
<!-- start -->
<PmtInfId>asd</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<BtchBookg>false</BtchBookg>
<PmtTpInf>
<InstrPrty>NORM</InstrPrty>
<SvcLvl>
<Prtry>test</Prtry>
</SvcLvl>
</PmtTpInf>
<ReqdExctnDt>date</ReqdExctnDt>
<Dbtr>
<Nm>something</Nm>
<PstlAdr>
<AdrLine>addr 1</AdrLine>
</PstlAdr>
</Dbtr>
<!-- end -->
<CdtTrfTxInf>
<PmtId>
<InstrId>16082672122</InstrId>
<EndToEndId>16082672122</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="RON">2159.41</InstdAmt>
</Amt>
<CdtrAgt>
<FinInstnId>
<BIC>some bic</BIC>
</FinInstnId>
</CdtrAgt>
</CdtTrfTxInf>
</PmtInf>
</CstmrCdtTrfInitn>
</Document>
- 如您所见,我有多个 (4) 个
<PmtInf></PmtInf>部分,它们几乎具有相同的结构。 -
我想做的是:
- 比较来自第一个
PmtInf的<PmtInfId>asd</PmtInfId>和来自第二个PmtInf的<PmtInfId>asd</PmtInfId>。如果有完美匹配(如在相同的标签和文本中),移动到下一个标签元素并比较它们(<PmtMtd>TRF</PmtMtd>来自第一个PmtInf与<PmtMtd>TRF</PmtMtd>来自第二个PmtInf... 如果有在到达<CdtTrfTxInf>标签之前,总是完美匹配。 - 当我们到达
<CdtTrfTxInf>时,这意味着第一个PmtInf的第一部分与第二个PmtInf的第一部分相同。此时,将<CdtTrfTxInf></CdtTrfTxInf>从第二个PmtInf移到第一个PmtInf的<CdtTrfTxInf></CdtTrfTxInf>部分之后。然后,删除第二个PmtInf部分。
- 比较来自第一个
所以,此时,xml 应该是这样的:
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.03">
<CstmrCdtTrfInitn>
<GrpHdr>
<MsgId>123</MsgId>
<CreDtTm>321</CreDtTm>
<NbOfTxs>10</NbOfTxs>
<CtrlSum>18700.68</CtrlSum>
<InitgPty>
<Nm>some info</Nm>
</InitgPty>
</GrpHdr>
<PmtInf>
<!-- start -->
<PmtInfId>asd</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<BtchBookg>false</BtchBookg>
<PmtTpInf>
<InstrPrty>NORM</InstrPrty>
<SvcLvl>
<Prtry>test</Prtry>
</SvcLvl>
</PmtTpInf>
<ReqdExctnDt>date</ReqdExctnDt>
<Dbtr>
<Nm>something</Nm>
<PstlAdr>
<AdrLine>addr 1</AdrLine>
</PstlAdr>
</Dbtr>
<!-- end -->
<CdtTrfTxInf>
<PmtId>
<InstrId>16082672122</InstrId>
<EndToEndId>16082672122</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="RON">2159.41</InstdAmt>
</Amt>
<CdtrAgt>
<FinInstnId>
<BIC>some bic</BIC>
</FinInstnId>
</CdtrAgt>
</CdtTrfTxInf>
<CdtTrfTxInf>
<PmtId>
<InstrId>16082672122</InstrId>
<EndToEndId>16082672122</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="RON">2159.41</InstdAmt>
</Amt>
<CdtrAgt>
<FinInstnId>
<BIC>some bic</BIC>
</FinInstnId>
</CdtrAgt>
</CdtTrfTxInf>
</PmtInf>
<PmtInf>
<!-- start -->
<PmtInfId>qwe</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<BtchBookg>false</BtchBookg>
<PmtTpInf>
<InstrPrty>HIGH</InstrPrty>
<SvcLvl>
<Prtry>test</Prtry>
</SvcLvl>
</PmtTpInf>
<ReqdExctnDt>date</ReqdExctnDt>
<Dbtr>
<Nm>something</Nm>
<PstlAdr>
<AdrLine>addr 1</AdrLine>
</PstlAdr>
</Dbtr>
<!-- end -->
<CdtTrfTxInf>
<PmtId>
<InstrId>16082672122</InstrId>
<EndToEndId>16082672122</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="RON">2159.41</InstdAmt>
</Amt>
<CdtrAgt>
<FinInstnId>
<BIC>some bic</BIC>
</FinInstnId>
</CdtrAgt>
</CdtTrfTxInf>
</PmtInf>
<PmtInf>
<!-- start -->
<PmtInfId>asd</PmtInfId>
<PmtMtd>TRF</PmtMtd>
<BtchBookg>false</BtchBookg>
<PmtTpInf>
<InstrPrty>NORM</InstrPrty>
<SvcLvl>
<Prtry>test</Prtry>
</SvcLvl>
</PmtTpInf>
<ReqdExctnDt>date</ReqdExctnDt>
<Dbtr>
<Nm>something</Nm>
<PstlAdr>
<AdrLine>addr 1</AdrLine>
</PstlAdr>
</Dbtr>
<!-- end -->
<CdtTrfTxInf>
<PmtId>
<InstrId>16082672122</InstrId>
<EndToEndId>16082672122</EndToEndId>
</PmtId>
<Amt>
<InstdAmt Ccy="RON">2159.41</InstdAmt>
</Amt>
<CdtrAgt>
<FinInstnId>
<BIC>some bic</BIC>
</FinInstnId>
</CdtrAgt>
</CdtTrfTxInf>
</PmtInf>
</CstmrCdtTrfInitn>
</Document>
- 现在对第一个
PmtInf部分和第三个部分重复该过程,然后对第四个部分重复该过程。如果有几乎完美的匹配,我们应该只有一个PmtInf标签,里面有4个CdtTrfTxInf标签。 - 如果在某些时候不匹配(例如,将第一个
PmtInf中的<InstrPrty>NORM</InstrPrty>与第三个PmtInf中的<InstrPrty>HIGH</InstrPrty>进行比较时,请保留该PmtInf部分并转到下一个。 - 在我们将第一个
PmtInfs 与它上面的所有PmtInfs进行比较后,将第二个PmtInf与第三个比较并应用相同的规则,然后将第三个与第四个...以此类推。
现在我可能要求太多了,但是这可以用 XSLT 完成吗?我知道我没有尝试任何事情,但我只是花了太多时间尝试通过简单的 Python 字符串操作来实现这一点,而且看起来 XSLT 转换文档需要一些时间来适应语法。
我这样调用脚本:
def parse_xml(file, output_path):
parser = ET.XMLParser(encoding='utf-8', recover=True)
dom = ET.parse(file, parser=parser)
xslt = ET.fromstring(TEMPLATE_XSLT) # TEMPLATE_XSLT contains the transformation
transform = ET.XSLT(xslt)
new_dom = transform(dom)
with open(output_path, 'wb') as xml_file:
xml_file.write(new_dom)
【问题讨论】:
-
你可以使用 XSLT 2.0 吗?如果是,请查看:w3.org/TR/xpath-functions/#func-deep-equal
-
显然,来自 Python 的
lxml模块只允许 v1.0,所以我想我必须坚持下去。你有时间帮我解决这个问题吗?它看起来像是一种很棒的转换语言,我真的没有完全理解。欢迎任何解释! -
恐怕这是一项艰巨的任务。查看 stackoverflow.com/questions/33610324/… 了解深度相等的 XSLT 1.0 实现。
-
是的,我看到了……但我想我需要一些指导。至少,某种伪代码可以让我开始。
-
为什么说要比较的部分有几乎相同的结构?在给定的示例中,它们都具有完全相同的结构 - 如果该结构是恒定的,您可以通过显式列出要比较的节点来进行比较。这会很冗长,但很容易。
标签: xml python-3.x xslt