【问题标题】:Create XML with only distinct paths using XSLT使用 XSLT 创建仅具有不同路径的 XML
【发布时间】:2013-12-10 18:16:21
【问题描述】:

我想创建一个仅包含在源文档中具有不同路径的节点名称的 XML。该值在这里并不重要,它可以是空值或虚拟值。换句话说,生成的文档应该只包含源文档的(节点)本质。

我找到了一个非常相似的问题的答案(链接:How to list complete XML document using XSLT),它指向了正确的方向,但并不是我想要的。

使用上述帖子的修改示例:

源文档:

<?xml version="1.0" encoding="UTF-8"?>
<MediaCatalog name="AccessoriesCatalog">
    <Category Definition="AccessoriesCategory"
    name="1532" id="1532">
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16115" id="16115">
        <ParentCategory>1532</ParentCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16116" id="16116">
        <ParentCategory>16115</ParentCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16126" id="16126">
        <ParentCategory>16115</ParentCategory>
            <genre>
                <id>17</id>
                <name>Fairy Tales</name>
           </genre>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16131" id="16131">
        <ParentCategory>1532</ParentCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16132" id="16132">
        <ParentCategory>16131</ParentCategory>
            <language>
                <id>1</id>
                <name>English</name>
                <shortName>EN</shortName>
            </language>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16136" id="16136">
        <ParentCategory>16131</ParentCategory>
            <genre>
                <id>18</id>
                <name>Thriller</name>
           </genre>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16139" id="16139">
        <ParentCategory>16131</ParentCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16144" id="16144">
        <ParentCategory>16131</ParentCategory>
        <subCategory>
            <label>
                <id>444</id>
                <name>label444</name>
            </label>
        </subCategory>
    </Category>
    <Category Definition="AccessoriesCategory"
    name="16195" id="16195">
        <ParentCategory>16131</ParentCategory>
    </Category>
</MediaCatalog>

生成的文档应如下所示:

<MediaCatalog>
    <Category>
        <ParentCategory>
        </ParentCategory>
        <genre>
            <id></id>
            <name></name>
        </genre>
        <language>
            <id></id>
            <name></name>
            <shortName></shortName>
        </language>
        <subCategory>
            <label>
                <id></id>
                <name></name>
            </label>
        </subCategory>
    </Category>
</MediaCatalog>

根据我为类似问题找到的答案,我提出了以下转换来实现这一目标:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="xml" encoding="UTF-8"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kElemByName" match="*" use="local-name()"/>

 <xsl:template match="
  *[generate-id()
   =
    generate-id(key('kElemByName', local-name())[1])
   ]">
  <xsl:value-of select="concat('&lt;', local-name(), '&gt;', '&#xA;')" disable-output-escaping="yes" />
  <xsl:apply-templates select="*"/>
  <xsl:value-of select="concat('&lt;/', local-name(), '&gt;', '&#xA;')" disable-output-escaping="yes" />
 </xsl:template>
 <xsl:template match="text()">
 </xsl:template>
</xsl:stylesheet>

但这并没有给我正确的答案,因为 Muenchian 分组方法的键仅基于使用函数 local-name() 的节点名称。

所以将它应用到我得到的源 xml 上面,而不是正确的输出是:

<?xml version="1.0" encoding="UTF-8"?>
<MediaCatalog>
    <Category>
    </Category>
    <ParentCategory>
    </ParentCategory>
    <genre>
        <id>
        </id>
        <name>
        </name>
    </genre>
    <language>
        <shortName>
        </shortName>
    </language>
    <subCategory>
        <label>
        </label>
    </subCategory>
</MediaCatalog>

为了创建正确的输出,必须使用完整的节点路径作为键,而不是仅使用节点名称。问题是这在 XSLT 中是如何实现的,因为据我所知,没有诸如 getFullPath() 之类的内置函数来获取当前节点的完整路径。

【问题讨论】:

  • 你能用node-set()吗?
  • 嗨竖琴!谢谢你的建议。我在这里不受任何约束。任何工作都很好。尽管如此,我还是想确保坚持使用 XSLT 的标准功能,而不是依赖于处理器的东西。所有标准 XSLT 1.0、2.0 或 3.0 实现中都应该有一个可行的解决方案。
  • 使用完整路径是不够的。您可以使用有限的路径函数(例如concat(local-name((ancestor::*)[1]), local-name((ancestor::*)[2]), local-name((ancestor::*)[3])))轻松测试这一点。问题是如果本地名称被视为组开始,模板只会下降到子树,因此甚至不会测试具有更深嵌套级别的后续子树。
  • 我认为完全递归的&lt;for-each-group&gt; 可以完成这项工作。这需要 XSLT 2.0。当然,您也可以在 1.0 中使用 Muenchian Grouping 进行此操作,但为高效执行定义和不定数量的索引可能很困难。
  • 嗨,马库斯!谢谢!如果我理解正确,您的意思是递归使用 之类的东西,对吗?我必须使用什么作为键(??? 部分)?与上面我的 xsl 1.0 转换中使用的 Muenchian 分组方法一样,我遇到了定义正确键的问题。有什么建议吗?

标签: xml xslt


【解决方案1】:

以下 XSLT 产生所需的输出(除了没有很好缩进的事实):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet 
    version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes" />
  <xsl:strip-space elements="*"/>

  <!-- Template for recursive handling of the child nodes. 
       Note that these nodes originate from different parents belonging to the same group! 
       This is important since we have to scan ALL sub trees of the a group and not only the first one!
  -->
  <xsl:template name="descend">
    <xsl:param name="nodes"/>

    <xsl:for-each-group select="$nodes" group-by="local-name()">

      <xsl:value-of select="concat('&lt;', current-grouping-key(), '&gt;', '&#xA;')" disable-output-escaping="yes" />

      <xsl:call-template name="descend">
        <!-- Call recursively. -->
        <xsl:with-param name="nodes" select="current-group()/*"/>
      </xsl:call-template>

      <xsl:value-of select="concat('&lt;/', current-grouping-key(), '&gt;', '&#xA;')" disable-output-escaping="yes" />

    </xsl:for-each-group>
  </xsl:template>

  <!-- Start the recursion with the children of the root node. -->
  <xsl:template match="/">
    <xsl:call-template name="descend">
      <xsl:with-param name="nodes" select="*"/>
    </xsl:call-template>    
  </xsl:template>

</xsl:stylesheet>

【讨论】:

  • 嘿马库斯!效果很好!惊人的!我花了很多时间来寻找解决方案,您很快就会找到答案。非常令人印象深刻!非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-01-18
  • 1970-01-01
  • 2011-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多