使用XSLT重命名节点

时间:2008-11-07 04:06:52

标签: xml vb.net xslt

我正在尝试一些非常简单的事情,但由于某种原因它不起作用。基本上,我需要重命名XML文档中的一些节点。因此,我创建了一个XSLT文件来进行转换。

以下是XML的示例:

编辑:地址和地址元素出现在许多级别。这就是我必须尝试应用XSLT的原因。 Visual Studio类型化数据集功能(从XSD文件创建类型化数据集)不允许您对同一个表具有嵌套引用。因此,拥有企业/业务/地址和企业/业务/联系人/地址会导致Load()失败。这是一个已知的问题,他们告诉你的只是“没有嵌套的表引用...编辑你的XSD以阻止它。”不幸的是,这意味着我们必须应用XSLT使XML符合“被黑”的XSD,因为这些文件来自第三方供应商。

所以,我们非常接近这里提供的帮助。最后几件事是这些:

1.。)如何在xsl:template的match属性中使用命名空间引用,以指定我要将Businessinesses / Business / Addresses重命名为BusinessAddresses,但重命名为Businessities / Business / Contacts / Contact / Addresses联系地址?

2.。)如何使用显式命名空间引用阻止XSLT混乱每个新元素?它导致输出极度膨胀。

我创建了一个名为“steel”的命名空间,并且取得了很好的成功:

<xsl:template match="steel:Addresses>
  <xsl:element name="BusinessAddresses>
</xsl:template>

这里显而易见的问题是,它将地址元素的 ALL 重命名为BusinessAddresses,即使我想要其中一些命名为ContactAddresses,依此类推。不必要地向所有重命名的节点添加显式命名空间引用也很麻烦。

我尝试了这种方法,但是只要在match属性中添加斜杠,它就是XSLT中的语法错误,如下所示:

<xsl:template match="steel:/Businesses/Business/Addresses">

我感觉非常接近,但需要一些关于如何混合命名空间用法和使用斜杠在特定路径下选择 ANY 节点的方法的指导。

<?xml version="1.0"?>
<Businesses>
  <Business>
    <BusinessName>Steel Stretching</BusinessName>
    <Addresses>
      <Address>
        <City>Pittsburgh</City>
      </Address>
      <Address>
        <City>Philadelphia</City>
      </Address>
    </Addresses>
    <Contacts>
      <Contact>
        <FirstName>Paul</FirstName>
        <LastName>Jones</LastName>
        <Addresses>
          <Address>
            <City>Pittsburgh</City>
          </Address>
        </Addresses>
      </Contact>
    </Contacts>
  </Business>
  <Business>
    <BusinessName>Iron Works</BusinessName>
    <Addresses>
      <Address>
        <City>Harrisburg</City>
      </Address>
      <Address>
        <City>Lancaster</City>
      </Address>
    </Addresses>
  </Business>
</Businesses>

我需要将地址重命名为BusinessAddresses,我需要将Address更改为BusinessAddress,直接在Business节点下为地址和地址的每个实例重命名。我还需要将地址重命名为ContactAddresses,我需要将地址重命名为ContactAddress,直接在联系节点下为地址和地址的每个实例重命名。

我尝试了几种解决方案,但似乎都没有。它们最终都会生成与原始文件相同的XML。

这是我尝试过的一个例子:

  <xsl:template match="/">
    <xsl:apply-templates select="@*|node()" />
  </xsl:template>

  <xsl:template match="@*|*">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Addresses">
    <BusinessAddresses>
      <xsl:apply-templates select="@*|node()" />
    </BusinessAddresses>
  </xsl:template>

已经尝试过至少6种不同的版本,完成了在VB.Net中逐步调试XSLT调试器。它永远不会执行地址的模板匹配。

为什么?

2 个答案:

答案 0 :(得分:10)

为什么XSLT会失败?

由于像拼写错误这样的显而易见的事情,XSLT会失败。但是,最可能的情况与名称空间使用有关。如果您为XML声明了默认命名空间但未在XSLT中包含该命名空间,则XSLT将无法与您期望的模板匹配。

以下示例添加xmlns:business属性,该属性声明由business前缀限定的项属于名称空间mynamespace.uri。然后我使用此前缀来限定地址和地址模板匹配。当然,您需要将命名空间URI更改为与XML文件的默认命名空间匹配的任何内容。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
                xmlns:business="mynamespace.uri"
                exclude-result-prefixes="msxsl">
  <xsl:template match="/">
    <xsl:apply-templates select="@*|node()"/>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="business:Addresses">
    <xsl:element name="BusinessAddresses">
      <xsl:apply-templates select="@*|node()" />
    </xsl:element>
  </xsl:template>

  <xsl:template match="business:Address">
    <xsl:element name="BusinessAddress">
      <xsl:apply-templates select="@*|node()"/>
    </xsl:element>
  </xsl:template>
</xsl:stylesheet>

如何根据元素位置和名称匹配模板?

有几种方法可以实现问题的最后一部分,即BusinessAddress或ContactAddress,但最简单的方法是修改模板match属性以考虑父节点。如果您将match属性视为节点的XML路径,则此选项会变得更加清晰(为简洁起见,模板的内容):

<xsl:template match="business:Business/business:Addresses>
</xsl:template>

<xsl:template match="business:Business/business:Addresses/business:Address">
</xsl:template>

<xsl:template match="business:Contact/business:Addresses">
</xsl:template>

<xsl:template match="business:Contact/business:Addresses/business:Address">
</xsl:template>

如果match仅基于元素名称,则存在实现此目的的其他方法,但是它们更难实现,遵循和维护,因为它们涉及在父节点层次结构上使用条件检查正在处理的元素,都在模板中。

答案 1 :(得分:0)

也许这就是,如果您展示的数据非常类似于您的工作

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="Businesses">
 <Businesses>
  <xsl:apply-templates/>
 </Businesses>
</xsl:template>

<xsl:template match="*">
 <xsl:copy-of select="."/>
</xsl:template>

<xsl:template match="Addresses">
 <BusinessAddresses>
  <xsl:apply-templates/>
 </BusinessAddresses>
</xsl:template>

<xsl:template match="Addresses/Address">
 <BusinessAddress>
  <xsl:value-of select="."/>
 </BusinessAddress>
</xsl:template>

</xsl:stylesheet>