以下是XML的示例:
编辑:地址和地址元素出现在许多级别.这就是我必须尝试应用XSLT的原因. Visual Studio类型化数据集功能(从XSD文件创建类型化数据集)不允许您对同一个表具有嵌套引用.因此,拥有企业/业务/地址和企业/业务/联系人/地址会导致Load()失败.这是一个已知的问题,他们告诉你的只是“没有嵌套的表引用…编辑你的XSD以阻止它.”不幸的是,这意味着我们必须应用XSLT使XML符合“被黑”的XSD,因为这些文件来自第三方供应商.
所以,我们非常接近这里提供的帮助.最后几件事是这些:
1.)如何在xsl:template的match属性中使用命名空间引用,以指定我要将Businessinesses / Business / Addresses重命名为BusinessAddresses,但是将Businessities / Business / Contacts / Contact / Addresses重命名为ContactAddresses?
2.)如何通过显式命名空间引用阻止XSLT混乱每个新元素?它导致输出极度膨胀.
我创建了一个名为“steel”的命名空间,并且取得了很好的成功:
<xsl:template match="steel:Addresses> <xsl:element name="BusinessAddresses> </xsl:template>
这里显而易见的问题是它将所有地址元素重命名为BusinessAddresses,即使我想要其中一些名为ContactAddresses,依此类推.不必要地向所有重命名的节点添加显式命名空间引用也很麻烦.
我试过这种事情,但是只要我在match属性中添加斜杠,它就是XSLT中的语法错误,如下所示:
<xsl:template match="steel:/Businesses/Business/Addresses">
我觉得非常接近,但需要一些关于如何混合命名空间用法和使用斜杠来选择特定路径下的任何节点的方法的指导.
<?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,我需要将地址重命名为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调试器.它永远不会执行地址的模板匹配.
为什么?
由于像拼写错误这样的显而易见的事情,XSLT会失败.但是,最可能的情况与名称空间使用有关.如果您为XML声明了默认命名空间但未在XSLT中包含该命名空间,则XSLT将不会像您期望的那样匹配模板.
以下示例添加xmlns: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属性视为节点的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>
如果匹配仅基于元素名称,则存在实现此目的的其他方法,但是它们更难实现,跟随和维护,因为它们涉及在正在处理的元素的父节点层次结构上使用条件检查,所有这些方法都在模板.