任务是清除XML文件中以下CustomerIdentity
元素中的任何非数字字符:
<ns2:TaxAtSource institutionID="#SG">
<ns2:CantonID>SG</ns2:CantonID>
<ns2:CustomerIdentity>CHE123.456 </ns2:CustomerIdentity>
</ns2:TaxAtSource>
我尝试了sed(它会很优雅,但由于非数字字符可以在CustomerIdentity
标记之间的任何位置,所以正则表达式有点麻烦)。我也尝试过XSLT,但是名称空间ns2在识别标记(非引用名称空间)时遇到了麻烦。因此,如果有人有一个有效的解决方案来处理XML文件,则如下所示(其余部分应该保持不变):
<ns2:TaxAtSource institutionID="#SG">
<ns2:CantonID>SG</ns2:CantonID>
<ns2:CustomerIdentity>123456</ns2:CustomerIdentity>
</ns2:TaxAtSource>
我们将不胜感激。一位同事建议使用AWK或ruby,但我认为这也可以归结为regex。
编辑:我已经从xsl中尝试了以下XSLT,删除了所有非数字字符和前导1:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="text()">
<xsl:variable name="vnumsOnly" select=
"translate(., translate(.,'0123456789',''), '')
"/>
<xsl:value-of select=
"substring($vnumsOnly, (substring($vnumsOnly,1,1)='1') +1)"/>
</xsl:template>
</xsl:stylesheet>
但这并没有完全奏效。
我引用你自己的答案:
正如你已经提到的,它只需要良好地形成,所以"faked"命名空间声明成功。我必须使用1.0版本,因为我的xsltproc似乎只支持那个版本:
不是,看看这里。你看到任何非数字字符被删除了吗?
事实上,恰恰相反。是任意的前缀和唯一标识命名空间的完整命名空间声明。换句话说,元素
<ns2:CustomerIdentity>
其中xmlns:ns2="swissdec.ch/schema/sd/20130514/SalaryDeclaration"
和
<ns2:CustomerIdentity>
其中xmlns:ns2="www.testing.com"
是不同的元素。另一方面,
<ns2:CustomerIdentity>
其中xmlns:ns2="swissdec.ch/schema/sd/20130514/SalaryDeclaration"
和
<other:CustomerIdentity>
其中xmlns:other="swissdec.ch/schem/sd/2013051/SalaryDeclaration"
识别相同的元素。因此,当您转换XML文档并需要访问单个元素时,您需要声明与源文档中完全相同的名称空间,但您可以为其选择另一个前缀。
样式表
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0"
xmlns:ns2="swissdec.ch/schema/sd/20130514/SalaryDeclaration">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="ns2:CustomerIdentity/text()">
<xsl:value-of
select="translate(., translate(.,'0123456789',''), '')"/>
</xsl:template>
</xsl:transform>
XML输入
<ns2:TaxAtSource institutionID="#SG"
xmlns:ns2="swissdec.ch/schema/sd/20130514/SalaryDeclaration">
<ns2:CantonID>SG</ns2:CantonID>
<ns2:CustomerIdentity>CHE123.456 </ns2:CustomerIdentity>
</ns2:TaxAtSource>
XML输出
<?xml version="1.0" encoding="UTF-8"?>
<ns2:TaxAtSource
xmlns:ns2="swissdec.ch/schema/sd/20130514/SalaryDeclaration"
institutionID="#SG">
<ns2:CantonID>SG</ns2:CantonID>
<ns2:CustomerIdentity>123456</ns2:CustomerIdentity>
</ns2:TaxAtSource>
您可以使用XSLT2.0的替换功能;
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"
xmlns:ns2="www.testing.com"
exclude-result-prefixes="ns2">
<xsl:output method="xml" indent="yes" />
<xsl:template match="ns2:CustomerIdentity">
<ns2:CustomerIdentity>
<xsl:value-of select='replace(., "[a-zA-Z. ]+","")'/>
</ns2:CustomerIdentity>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
正如我编辑自己的问题一样,我看到了一种方法(也多亏了xsl删除了所有非数字字符和前导1)。正如您已经提到的,它只需要格式良好,所以"faked"命名空间声明就可以了。我必须使用1.0版本,因为我的xsltproc似乎只支持这个版本:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:ns2="www.testing.com" exclude-result-prefixes="ns2">
<xsl:output method="xml" indent="yes" />
<xsl:template match="text()">
<xsl:variable name="vnumsOnly" select=
"translate(., translate(.,'0123456789',''), '')
"/>
<xsl:value-of select=
"substring($vnumsOnly, (substring($vnumsOnly,1,1)='1') +1)"/>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
谢谢你把我引导到正确的方向!