使用 XSLT 重命名节点 [英] Rename nodes with XSLT

查看:35
本文介绍了使用 XSLT 重命名节点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying something very simple, but for some reason it does not work. Basically, I need to rename some nodes in an XML document. Thus, I created an XSLT file to do the transformation.

以下是 XML 的示例:

Here is an example of the XML:

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

Addresses and Address elements occur at many levels. This is what caused me to have to try and apply an XSLT. The Visual Studio typed dataset feature, which creates typed datasets from XSD files does not permit you to have nested references to the same table. Thus, having Businesses/Business/Addresses and Businesses/Business/Contact/Addresses causes the Load() to fail. This is a known issue, and all they tell you is something like "Don't have nested table references...edit your XSD to stop having that." Unfortunately, this means that we have to apply XSLT to make the XML conform to the "hacked" XSD, since the files are coming from a third party vendor.

因此,我们非常接近此处提供的帮助.最后几件事是:

So, we are very close with the help rendered here. The last couple of things are these:

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

1.) How can I use the namespace reference in the match attribute of the xsl:template in order to specify that I want to rename Businesses/Business/Addresses to BusinessAddresses, but rename Businesses/Business/Contacts/Contact/Addresses to ContactAddresses?

2.) 我怎样才能阻止 XSLT 用显式命名空间引用来混淆每个新元素?它导致输出极度膨胀.

2.) How can I stop the XSLT from cluttering every new element with explicit namespace references? It is causing extreme bloat in the output.

我创建了一个名为steel"的命名空间,并在以下方面取得了成功:

I created a namespace called "steel", and was having good success with:

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

这里明显的问题是它将ALL Addresses 元素重命名为BusinessAddresses,即使我希望其中一些元素命名为ContactAddresses,等等.对所有重命名的节点不必要地添加显式命名空间引用也很麻烦.

The obvious problem here is that it renames ALL of the Addresses elements to BusinessAddresses, even though I want some of them named ContactAddresses, and so on. The needless addition of explicit namespace references to all of the renamed nodes is also troublesome.

我尝试过这种方法,但是一旦我向 match 属性添加斜杠,就会出现 XSLT 中的语法错误,如下所示:

I tried this sort of thing, but as soon as I add slashes to the match attribute, it is a a syntax error in the XSLT, like so:

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

我觉得很接近,但需要一些指导,了解如何混合使用命名空间和使用斜杠选择特定路径下的ANY节点.

I feel very close, but need some guidance on how to mix both the namespace usage and a way to use the slashes to select ANY nodes under specific paths.

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

我需要将 Addresses 重命名为 BusinessAddresses,并且我需要将 Address 重命名为 BusinessAddress,对于直接在 Business 节点下的 Addresses 和 Address 的每个实例.我还需要将地址重命名为 ContactAddresses,并且我需要将地址重命名为 ContactAddress,对于直接在联系节点下的地址和地址的每个实例.

I need to rename Addresses to BusinessAddresses, and I need to rename Address to BusinessAddress, for every instance of Addresses and Address directly under a Business node. I also need to rename Addresses to ContactAddresses, and I need to rename Address to ContactAddress, for every instance of Addresses and Address directly under a Contact Node.

我尝试了多种解决方案,但似乎都不起作用.它们最终都会生成与原始文件相同的 XML.

I have tried several solutions, but none seem to work. They all end up producing the same XML as the original file.

以下是我尝试过的示例:

Here is an example of what I have tried:

  <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 调试器的单步调试.它从不执行地址模板匹配.

This has been tried in at least 6 different flavors, complete with stepping through the XSLT debugger in VB.Net. It never executes the template match for Addresses.

为什么?

推荐答案

为什么 XSLT 会失败?

XSLT 会因为诸如拼写错误之类的明显问题而失败.但是,最可能的情况与命名空间使用有关.如果您为 XML 声明了默认名称空间,但未在 XSLT 中包含该名称空间,则 XSLT 将与您预期的模板不匹配.

Why might an XSLT fail?

An XSLT will fail because of obvious things like typos. However, the most likely situation relates to namespace usage. If you declared a default namespace for your XML but don't include that in your XSLT, the XSLT won't match the templates as you might expect.

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

The following example adds the xmlns:business attribute which declares that items qualified by the business prefix belong to the namespace mynamespace.uri. I then used this prefix to qualify the Address and Addresses template matches. Of course, you will need to change the namespace URI to whatever matches the default namespace of your XML file.

<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 路径,则此选项会变得更清晰(为简洁起见,模板内容被省略):

How do you match templates based on element location as well as name?

There are several ways to achieve this last part to your problem, BusinessAddress or ContactAddress, but the easiest is to modify the template match attributes to consider parent nodes. If you think of the match attribute as a path into the XML for a node, this option becomes clearer (contents of templates left out for brevity):

<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 仍然仅基于元素名称,则存在其他方法来实现这一点,但它们更难实现、遵循和维护,因为它们涉及对父级的条件检查正在处理的元素的节点层次结构,都在模板中.

Other methods exist for achieving this if the match remains based on just the element name, but they're harder to implement, follow, and maintain as they involve the use of conditional checks on the parent node hierarchy of the element being processing, all within the template.

这篇关于使用 XSLT 重命名节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆