XSLT:使用父节点的命名空间

时间:2010-01-05 23:37:03

标签: xml xslt datacontractserializer

我想避免在我的XSLT输出中产生重复的命名空间。

(我正在使用XSLT来按摩一些XML,以便Microsoft的DataContractSerializer认为适合实际处理它.DCS似乎不喜欢的一件事是多次定义相同的命名空间。)

我从XXX元素下获取所有“特征”元素,并将它们组合在一个新的数组元素中,如下所示:

<xsl:stylesheet version="1.0" 
              xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
              xmlns:feature="some namespace">
<xsl:template match="feature:XXX">
  <xsl:copy>
    <feature:Characteristics>
      <xsl:apply-templates select="feature:Characteristics"/>
     </feature:Characteristics>
    <xsl:copy-of select="*[not(self::feature:Characteristics)]" />
  </xsl:copy>
</xsl:template>
<xsl:template match="feature:Characteristics">
  <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <xsl:value-of select="." />
  </arrays:unsignedShort>
</xsl:template>
</xsl:stylesheet>

“feature”命名空间在XSLT文件的顶部定义。但是,在源XML中不会找到值“feature”,它将是一些任意前缀(通常为“h”)。问题是如果我使用这个XSLT,那么命名空间被分配给输出XML中的2个前缀:来自输入XML的原始命名空间(通常是“h”)和XSLT生成的“特征”。 (虽然有效的XML,但这会让可怜的微软感到困惑。)

所以我想通过改为引用当前元素的命名空间来完全避免在输出XML中定义“feature”命名空间。我试过这个变种,但我不知道如何正确设置xsl:element的命名空间值,以获取当前上下文节点的命名空间前缀......

<xsl:stylesheet version="1.0" 
              xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
              xmlns:feature="some namespace">
  <xsl:template match="feature:XXX">
   <xsl:copy>
    <xsl:element name="Characteristics" namespace="{???}">
      <xsl:apply-templates select="feature:Characteristics"/>
    </xsl:element>
    <xsl:copy-of select="*[not(self::feature:Characteristics)]" />
  </xsl:copy>
</xsl:template>
  <xsl:template match="feature:Characteristics">
  <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <xsl:value-of select="." />
  </arrays:unsignedShort>
</xsl:template>
</xsl:stylesheet>

示例输入:

<h:XXX xmlns:h="http://stackoverflow.com">
 <h:Characteristics>7</h:Characteristics>
 <h:Characteristics>11</h:Characteristics>
 <h:Characteristics>12</h:Characteristics>
 <h:ProductName>blah</h:ProductName>
 <h:Vendor>blah</h:Vendor>
 <h:Version></h:Version>
</h:XXX>

重复名称空间(不好):

<h:XXX xmlns:h="http://stackoverflow.com">
 <feature:Characteristic xmlns:feature="http://stackoverflow.com">
      <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">7</arrays:unsignedShort>
      <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">11</arrays:unsignedShort>
      <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">12</arrays:unsignedShort>
 </feature:Characteristic>
 <h:ProductName>blah</h:ProductName>
 <h:Vendor>blah</h:Vendor>
 <h:Version></h:Version>
</h:XXX>

期望的输出:

<h:XXX xmlns:h="http://stackoverflow.com">
 <h:Characteristic>
      <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">7</arrays:unsignedShort>
      <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">11</arrays:unsignedShort>
      <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">12</arrays:unsignedShort>
 </h:Characteristic>
 <h:ProductName>blah</h:ProductName>
 <h:Vendor>blah</h:Vendor>
 <h:Version></h:Version>
</h:XXX>

这个XSLT几乎可以工作,但它涉及硬编码“h”值,我想支持一个任意值:

<?xml version ="1.0" encoding="iso-8859-1"?>
  <xsl:stylesheet version="1.0" 
              xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
              xmlns:feature="some ns"
              xmlns:h="some ns"
              exclude-result-prefixes="h">

<xsl:template match="feature:XXX">
  <xsl:copy>
    <h:Characteristic>
      <xsl:apply-templates select="feature:Characteristics"/>
    </h:Characteristic>
    <xsl:copy-of select="*[not(self::feature:Characteristics)]" />
  </xsl:copy>
</xsl:template>

<xsl:template match="feature:Characteristics">
  <arrays:unsignedShort xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <xsl:value-of select="." />
  </arrays:unsignedShort>
 </xsl:template>

 </xsl:stylesheet>

3 个答案:

答案 0 :(得分:1)

我刚删除了feature名称空间;如果我理解正确,它将包含与h相同的URI,对吧?

<xsl:stylesheet version="1.0"
              xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
              xmlns:h="http://stackoverflow.com">
  <xsl:output method="xml" indent="yes" />
  <xsl:template match="h:XXX" >
    <xsl:copy>
      <h:Characteristics>
        <xsl:apply-templates select="h:Characteristics"/>
      </h:Characteristics>
      <xsl:copy-of select="*[not(self::h:Characteristics)]" />
    </xsl:copy>
  </xsl:template>
  <xsl:template match="h:Characteristics">
    <arrays:unsignedShort 
        xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
      <xsl:value-of select="." />
    </arrays:unsignedShort>
  </xsl:template>
</xsl:stylesheet>

答案 1 :(得分:1)

这似乎对我有用,我相信必须有一个更简单的方法,但我现在想不到。所有这一切都使用 name()函数来获取根名称的前缀名称, substring-before()以获取前缀然后重建值并发出它们作为未转义的文本。

<xsl:stylesheet version="1.0" 
          xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
          xmlns:feature="http://stackoverflow.com"
      exclude-result-prefixes="feature" >
<xsl:template match="feature:XXX">
  <xsl:variable name="p" select="substring-before(name(), ':')"/>
  <xsl:copy>
   <xsl:value-of select="concat('&lt;', $p,':Characteristic', '&gt;')" disable-output-escaping="yes"/>
   <xsl:apply-templates select="feature:Characteristics"/>
   <xsl:value-of select="concat('&lt;/', $p,':Characteristic', '&gt;')" disable-output-escaping="yes"/>
   <xsl:copy-of select="*[not(self::feature:Characteristics)]" /> 
 </xsl:copy>
</xsl:template>
  <xsl:template match="feature:Characteristics">
   <arrays:unsignedShort 
       xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
     <xsl:value-of select="." />
   </arrays:unsignedShort>
 </xsl:template>
</xsl:stylesheet>

答案 2 :(得分:1)

如果您需要一致的名称空间前缀,则需要生成新元素,而不是 copy-of 。在XSLT中将名称空间前缀设置为您想要的名称(feature,h等)。

以下XSLT:

<xsl:stylesheet version="1.0"
              xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
              xmlns:feature="http://stackoverflow.com"
              xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
  <xsl:output method="xml" indent="yes" />

  <xsl:template match="feature:XXX">
   <xsl:element name="feature:XXX">
    <feature:Characteristic>
      <xsl:apply-templates select="feature:Characteristics"/>
    </feature:Characteristic>
    <xsl:apply-templates select="*[not(self::feature:Characteristics)]" />
  </xsl:element>
  </xsl:template>

  <xsl:template match="feature:Characteristics">
    <xsl:element name="arrays:unsignedShort">
        <xsl:value-of select="." />
    </xsl:element>
  </xsl:template>

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

</xsl:stylesheet>

生成以下输出:

<?xml version="1.0" encoding="UTF-16"?>
<feature:XXX xmlns:feature="http://stackoverflow.com">
 <feature:Characteristic xmlns:arrays="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
  <arrays:unsignedShort>7</arrays:unsignedShort>
  <arrays:unsignedShort>11</arrays:unsignedShort>
  <arrays:unsignedShort>12</arrays:unsignedShort>
 </feature:Characteristic>
 <feature:ProductName>blah</feature:ProductName>
 <feature:Vendor>blah</feature:Vendor>
 <feature:Version></feature:Version>
</feature:XXX>