我需要在最后一次冒号后得到每个数据的值。例如,我有这个文件:
<Data>
:20:PmtReferenceID000012
:21:Not used
:25: PHMNLBICXXX/Account00010203
:28c:00001/0001 (The 'c' in :28 can be either in upper or lower case)
:20:PmtReferenceID000012
:21:Not used
:25: PHMNLBICXXX/Account00010203
:28c:00001/0001 (The 'c' in :28 can be either in upper or lower case)
</Data>
我需要将':20:'后的值存储到<ABCD>
,':21:'到<EFGH>
,':25:'到<IJKL>
和':28c :'到<MNOP>
。
这是我的XSLT:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Data">
<Data>
<xsl:variable name="OneLine" select="replace(translate(.,' ', '|'),'
','')"/>
<ABCD>
<xsl:value-of select="substring-before(substring-after($OneLine, ':20:'),'|:')"/>
</ABCD>
<EFGH>
<xsl:value-of select="substring-before(substring-after($OneLine, ':21:'),'|:')"/>
</EFGH>
<IJKL>
<xsl:value-of select="substring-before(substring-after($OneLine, ':25:'),'|:')"/>
</IJKL>
<MNOP>
<xsl:value-of select="substring-before(substring-after($OneLine, ':28c:'),'|:')"/>
</MNOP>
</Data>
</xsl:template>
预期产出:
<Data>
<ABCD>PmtReferenceID000012</ABCD>
<EFGH>Not used</EFGH>
<IJKL> PHMNLBICXXX/Account00010203</IJKL>
<MNOP>00001/0001</MNOP>
</Data>
<Data>
<ABCD>PmtReferenceID000012</ABCD>
<EFGH>Not used</EFGH>
<IJKL> PHMNLBICXXX/Account00010203</IJKL>
<MNOP>00001/0001</MNOP>
</Data>
我做的是,我首先将回车替换为管道('|'),这样,如果我得到的值例如':20:',我将寻找'|'并在':20:'之后和'|'之前对值进行子串。有没有一个简单的方法我会在每个最后一个冒号之后获得值,因为有很多键,如果我要使用我做的方法?我正在考虑使用索引或位置,并存储所有键(:20:,:21:,:25:,:28c'),以便如果下一条记录包含':21:'或':25 :'或':28c',它将获得该键之前的值。但是,我不知道如何使用xslt。
非常感谢您的反馈!
谢谢,
答案 0 :(得分:3)
在XSLT 3.0中,您可以为不同的字符串编写模板,例如
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math" exclude-result-prefixes="xs math"
version="3.0">
<xsl:output indent="yes"/>
<xsl:template match="Data">
<xsl:copy>
<xsl:apply-templates select="tokenize(., '\r?\n')[normalize-space()]"/>
</xsl:copy>
</xsl:template>
<xsl:template match=".[. instance of xs:string and matches(., '^:20:')]">
<ABCD>
<xsl:value-of select="replace(., '^:20:', '')"/>
</ABCD>
</xsl:template>
<xsl:template match=".[. instance of xs:string and matches(., '^:21:')]">
<EFGH>
<xsl:value-of select="replace(., '^:21:', '')"/>
</EFGH>
</xsl:template>
<xsl:template match=".[. instance of xs:string and matches(., '^:25:')]">
<IJKL>
<xsl:value-of select="replace(., '^:25:', '')"/>
</IJKL>
</xsl:template>
<xsl:template match=".[. instance of xs:string and matches(., '^:28c:', 'i')]">
<MNOP>
<xsl:value-of select="replace(., '^:28c:', '', 'i')"/>
</MNOP>
</xsl:template>
</xsl:stylesheet>
使用Saxon 9.8或Altova XMLSpy / Raptor完成工作和输出
<Data>
<ABCD>PmtReferenceID000012</ABCD>
<EFGH>Not used</EFGH>
<IJKL> PHMNLBICXXX/Account00010203</IJKL>
<MNOP>00001/0001</MNOP>
</Data>
(输入
<Data>
:20:PmtReferenceID000012
:21:Not used
:25: PHMNLBICXXX/Account00010203
:28c:00001/0001
</Data>
)
作为替代方案,您可以使用analyze-string
函数并匹配返回的fn:match
元素,而不是标记和处理字符串:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs fn math"
version="3.0">
<xsl:output indent="yes"/>
<xsl:template match="Data">
<xsl:copy>
<xsl:apply-templates select="analyze-string(., '^(:[0-9]+[a-z]*:)(.*)\r?\n', 'im')//fn:match"/>
</xsl:copy>
</xsl:template>
<xsl:template match="fn:match[fn:group[@nr = 1][. = ':20:']]">
<ABCD>
<xsl:value-of select="fn:group[@nr = 2]"/>
</ABCD>
</xsl:template>
<xsl:template match="fn:match[fn:group[@nr = 1][. = ':21:']]">
<EFGH>
<xsl:value-of select="fn:group[@nr = 2]"/>
</EFGH>
</xsl:template>
<xsl:template match="fn:match[fn:group[@nr = 1][. = ':25:']]">
<IJKL>
<xsl:value-of select="fn:group[@nr = 2]"/>
</IJKL>
</xsl:template>
<xsl:template match="fn:match[fn:group[@nr = 1][matches(., '^:28c:', 'i')]]">
<MNOP>
<xsl:value-of select="fn:group[@nr = 2]"/>
</MNOP>
</xsl:template>
</xsl:stylesheet>
最后,采用map参数的思想来定义元素名称,第二个解决方案可以缩短为
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs fn math"
version="3.0">
<xsl:param name="map" as="map(xs:string, xs:string)"
select="map {
'20' : 'ABCD',
'21' : 'EFGH',
'25' : 'IJKL',
'28c' : 'MNOP'
}"/>
<xsl:output indent="yes"/>
<xsl:template match="Data">
<xsl:copy>
<xsl:apply-templates select="analyze-string(., '^(:([0-9]+[a-z]*):)(.*)\r?\n', 'im')//fn:match" mode="wrap"/>
</xsl:copy>
</xsl:template>
<xsl:template match="match" mode="wrap" xpath-default-namespace="http://www.w3.org/2005/xpath-functions">
<xsl:element name="{$map(lower-case(.//group[@nr = 2]))}">
<xsl:value-of select="group[@nr = 3]"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:2)
我是否有一个简单的方法可以在每个最后一个冒号之后得到值,因为有太多的键[...]
是。您可以使用RegEx匹配
在以下模板中,regex-group(2)
包含第二个/(最后一个)冒号后面的字符串。 regex-group(1)
包含密钥。
<xsl:template match="Data">
<Data>
<xsl:analyze-string select="." regex=":([0-9A-Za-z]+):(.*)\n">
<xsl:matching-substring>
(<xsl:value-of select="regex-group(1)" /> --- <xsl:value-of select="regex-group(2)" />)<xsl:text>
</xsl:text>
</xsl:matching-substring>
</xsl:analyze-string>
</Data>
</xsl:template>
部分输出:
(20 --- PmtReferenceID000012)
(21 --- Not used)
(25 --- PHMNLBICXXX/Account00010203)
(28c --- 00001/0001 (The 'c' in :28 can be either in upper or lower case))
通过它,您可以创建一个键/值Dictionary,用于在文本周围创建标签。
像这样:
例如:您可以在XSL文件中创建一个变量来存储映射:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:map="http://custom.map">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:variable name="Mapping">
<Map key="20">ABCD</Map>
<Map key="21">EFGH</Map>
<Map key="25">IJKL</Map>
<Map key="28c">MNOP</Map>
</xsl:variable>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Data">
<Data>
<xsl:analyze-string select="." regex=":([0-9A-Za-z]+):(.*)\n">
<xsl:matching-substring>
<xsl:element name="{$Mapping/Map[@key=regex-group(1)]/text()}"><xsl:value-of select="regex-group(2)" /></xsl:element>
</xsl:matching-substring>
</xsl:analyze-string>
</Data>
</xsl:template>
</xsl:stylesheet>
完整输出:
<?xml version="1.0" encoding="UTF-8"?>
<Data xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
xmlns:map="http://custom.map">
<ABCD>PmtReferenceID000012</ABCD>
<EFGH>Not used</EFGH>
<IJKL> PHMNLBICXXX/Account00010203</IJKL>
<MNOP>00001/0001 (The 'c' in :28 can be either in upper or lower case)</MNOP>
</Data>
或者你可以直接外包映射并为它们创建一个单独的文件......
答案 2 :(得分:0)
我在原帖中写了这个答案,但没有发布,因为它基本上与zx485发布的那个相似。
但是,我仍然建议使用key来检索相应的元素名称(我也认为正则表达式可以更简单,更健壮)。
我添加了一个标记步骤,将数据拆分为每个双换行字符的单独<Data>
包装。
XSLT 2.0
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="map">
<name key="20">ABCD</name>
<name key="21">EFGH</name>
<name key="25">IJKL</name>
<name key="28C">MNOP</name>
</xsl:variable>
<xsl:key name="nm" match="name" use="@key" />
<xsl:template match="Data">
<xsl:for-each select="tokenize(., '\n\n')">
<Data>
<xsl:analyze-string select="." regex="^:([^:]*):(.*)$" flags="m">
<xsl:matching-substring>
<xsl:element name="{key('nm', upper-case(regex-group(1)), $map)}">
<xsl:value-of select="regex-group(2)" />
</xsl:element>
</xsl:matching-substring>
</xsl:analyze-string>
</Data>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>