使用正则表达式从XML字符串中移除XML节点的命名空间前缀

6
我有一些存储在数据库中的遗留XML文档,它们作为BLOB存储,并且不是格式良好的XML。我从SQL数据库中读取它们,最终,由于我使用C#.NET,希望将它们实例化为XMLDocument。
当我尝试这样做时,显然会出现XMLException。查看XML文档后,发现它们全部失败,原因是特定XML节点中存在未声明的命名空间。
我不关心具有此前缀的任何XML节点,所以可以忽略它们或将它们丢弃。因此,基本上,在将字符串加载为XMLDocument之前,我想要从字符串中删除前缀,这样
<tem:GetRouteID>
        <tem:PostCode>postcode</tem:PostCode>
        <tem:Type>ItemType</tem:Type>
</tem:GetRouteID>

成为

<GetRouteID>
    <PostCode>postcode</PostCode>
    <Type>ItemType</Type>
</GetRouteID>

并且这个

<wsse:Security soapenv:actor="">
    <wsse:BinarySecurityToken>token</wsse:BinarySecurityToken>
</wsse:Security>

变成这样:

<Security soapenv:actor="">
    <BinarySecurityToken>token</BinarySecurityToken>
</Security>

我有一个解决方案,可以这样做:

我有一个解决方案,可以这样做:

<appSettings>
  <add key="STRIP_NAMESPACES" value="wsse;tem" />
</appSettings>

if (STRIP_NAMESPACES != null)
{
    string[] namespaces = Regex.Split(STRIP_NAMESPACES, ";");

    foreach (string ns in namespaces)
   {
        str2 = str2.Replace("<" + ns + ":", "<"); // Replace opening tag
        str2 = str2.Replace("</" + ns + ":", "</"); // Replace closing tag

    }
}

但理想情况下,我希望有一个通用的方法来实现这一点,这样就不必无休止地配置要删除的命名空间。

在C#.NET中如何实现这个目标。我认为使用正则表达式是正确的方式?

更新1

Ria提供的正则表达式对上述需求有效。但是,如果我还需要更改这个正则表达式,该怎么做呢?

<wsse:Security soapenv:actor="">
    <BinarySecurityToken>authtoken</BinarySecurityToken>
</Security>

变成这样?

<Security>
    <BinarySecurityToken>authtoken</BinarySecurityToken>
</Security>

更新2

根据Ria的回答,我想我已经自己弄清楚了更新版本,如下所示:

<(/?)\w+:(\w+/?) ?(\w+:\w+.*)?>

我认为使用正则表达式解析XML不是一个好主意。你可以使用XDocumentXElementXmlDocument(如果你使用的是.NET 2.0)。 - Leri
1
plb - 我认为OP不是在谈论使用正则表达式解析XML,而是通过编辑一些XML节点前缀使其符合规范,以便可以读入到一个xmldoc中。 - jim tollan
@jimtollan 是的,你说得对。我误解了问题。 - Leri
XML可以包含注释或CDATA吗? - svick
在我的具体示例中,XML 不能包含注释或 CDATA。但是,如果可以的话,会有什么影响? - brianilland
@uefa_celt 问题在于注释和CDATA部分都可以包含看起来像带有命名空间的XML元素的字符串,但实际上并不是(类似于<!-- <ns:elem -->),这可能会混淆正则表达式。 - svick
1个回答

9

更新

针对新问题(attribs命名空间),请尝试以下通用解决方案。这不会影响节点值:

Regex.Replace(originalXml, 
              @"((?<=</?)\w+:(?<elem>\w+)|\w+:(?<elem>\w+)(?==\"))", 
              "${elem}");

请在我的示例 XML 上尝试此正则表达式:

<wsse:Security soapenv:actor="dont match soapenv:actor attrib">
    <BinarySecurityToken>authtoken</BinarySecurityToken>
</Security> 

尝试使用XSL,您可以直接应用XSL或使用.NET中的XslTransform类进行应用:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="no"/>

<xsl:template match="/|comment()|processing-instruction()">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>

<xsl:template match="*">
    <xsl:element name="{local-name()}">
      <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
</xsl:template>

<xsl:template match="@*">
    <xsl:attribute name="{local-name()}">
      <xsl:value-of select="."/>
    </xsl:attribute>
</xsl:template>
</xsl:stylesheet>

或者尝试使用这个"正则表达式(Regex)":
var finalXml = Regex.Replace(originalXml, @"<(/?)\w+:(\w+/?)>", "<$1$2>");

当将XML加载到文档中时为什么不起作用,你认为这会起作用吗? - svick
我对问题进行了轻微更新。提供的正则表达式有效,但是有一些情况它无法匹配。请参见“更新1”下的示例。 - brianilland

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接