更改特定XML标记内的文本(摆脱非数字字符)

时间:2014-09-01 11:08:51

标签: xml regex xslt xslt-1.0

任务是删除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,但我认为这也归结为正则表达式。

编辑:我已经从xsl remove all non-numeric characters and leading 1尝试了以下XSLT:

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

但这并没有成功。

3 个答案:

答案 0 :(得分:2)

我引用你自己的回答:

  

正如你已经提到的,它只需要形成良好的形状,所以   “伪造的”命名空间声明解决了。我必须使用1.0版本   我的xsltproc似乎只支持该版本:

不是,看看here。您是否看到要删除的任何非数字字符?


实际上,情况恰恰相反。 前缀是任意的,并且是唯一标识命名空间的完整命名空间声明。换句话说,元素

<ns2:CustomerIdentity> 

其中xmlns:ns2 =“swissdec.ch/schema/sd/20130514/SalaryDeclaration”

<ns2:CustomerIdentity> 

其中xmlns:ns2 =“www.testing.com”

就XML解析器而言,

不同的元素。另一方面,

<ns2:CustomerIdentity> 

其中xmlns:ns2 =“swissdec.ch/schema/sd/20130514/SalaryDeclaration”

<other:CustomerIdentity> 

其中xmlns:other =“swissdec.ch/schema/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>

答案 1 :(得分:1)

您可以使用XSLT 2.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>

答案 2 :(得分:0)

就像我编辑自己的问题一样,我看到了一种方式(也感谢xsl remove all non-numeric characters and leading 1)。正如您已经提到的那样,它只需要格式正确,因此“伪造”的命名空间声明可以解决。我必须使用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>

感谢您引导我走向正确的方向!