【问题标题】:How to get a list of the distinct element names plus their attribute names using XSLT如何使用 XSLT 获取不同元素名称及其属性名称的列表
【发布时间】:2014-11-26 10:43:50
【问题描述】:

我想使用 xslt“扫描”我的 xml 文件并获取不同元素名称的列表以及它们的属性名称。

我的 XML:

<?xml version="1.0" encoding="UTF-8"?>
<dictionary>
    <entry>
        <form type="hyperlemma" xml:lang="cu">
            <note type="editor's comment">CHECK</note>
            <orth>hlE1</orth>
        </form>
        <form type="lemma" xml:lang="cu">
            <orth>lE1</orth>
        </form>
        <form type="variant" xml:lang="cu">
            <orth>var5</orth>
        </form>
    </entry>
    <entry>
        <form type="hyperlemma" xml:lang="cu">
            <orth>hlE2</orth>
        </form>
        <form type="lemma" xml:lang="cu">
            <orth>lE2</orth>
        </form>
    </entry>
</dictionary>

How to list complete XML document using XSLT 中记录了获取不同元素名称列表的方法(请参阅 Dimitre Novatchev 的回答)。

使用这个样式表

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:output method="text"/>
    <xsl:strip-space elements="*" />

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

    <xsl:template match="
        *[generate-id()
        =
        generate-id(key('kElemByName', name(.))[1])
        ]">
        <xsl:value-of select="concat(name(.), '&#xA;')"/>
        <xsl:apply-templates select="*"/>
    </xsl:template>

    <xsl:template match="text()"/>

</xsl:stylesheet>

(正确的)输出是

dictionary
entry
form
note
orth

是否也可以获取属性名称?我想要以下输出

dictionary
entry
form type="hyperlemma" xml:lang="cu"
form type="lemma" xml:lang="cu"
form type="variant" xml:lang="cu"
note type="editor's comment"
orth

我如何做到这一点?

【问题讨论】:

    标签: xml xslt


    【解决方案1】:

    当您使用 XSLT 2.0 时,我只需使用 for-each-group 和根据名称和属性计算的分组键来解决它:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="xs"
        version="2.0">
        <xsl:output method="text"/>
        <xsl:strip-space elements="*" />
    
        <xsl:template match="/">
          <xsl:for-each-group select="//*" group-by="string-join((name(), @*/concat(name(), '=&quot;', ., '&quot;')), ' ')">
            <xsl:value-of select="concat(current-grouping-key(), '&#10;')"/>
          </xsl:for-each-group>
        </xsl:template>
    
    </xsl:stylesheet>
    

    输出

    dictionary
    entry
    form type="hyperlemma" xml:lang="cu"
    note type="editor's comment"
    orth
    form type="lemma" xml:lang="cu"
    form type="variant" xml:lang="cu"
    

    对我来说撒克逊 9.5。

    如果你想对输出进行排序,你可以使用

      <xsl:template match="/">
          <xsl:for-each-group select="//*" group-by="string-join((name(), @*/concat(name(), '=&quot;', ., '&quot;')), ' ')">
            <xsl:sort select="current-grouping-key()"/>
            <xsl:value-of select="concat(current-grouping-key(), '&#10;')"/>
          </xsl:for-each-group>
        </xsl:template>
    

    我就是这样得到的

    dictionary
    entry
    form type="hyperlemma" xml:lang="cu"
    form type="lemma" xml:lang="cu"
    form type="variant" xml:lang="cu"
    note type="editor's comment"
    orth
    

    我认为要获得一致的结果,代码还首先需要按名称对属性进行排序,因为我怀疑如果输入有 &lt;foo att1="value1" att2="value2"/&gt;&lt;foo att2="value2" att1="value1"/&gt;,那么您只需要一个元素输出。

    排序可以用

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:mf="http://example.com/mf"
        exclude-result-prefixes="xs mf"
        version="2.0">
        <xsl:output method="text"/>
        <xsl:strip-space elements="*" />
    
        <xsl:function name="mf:sort" as="attribute()*">
          <xsl:param name="attributes" as="attribute()*"/>
          <xsl:perform-sort select="$attributes">
            <xsl:sort select="name()"/>
          </xsl:perform-sort>
        </xsl:function>
    
        <xsl:template match="/">
          <xsl:for-each-group select="//*" group-by="string-join((name(), mf:sort(@*)/concat(name(), '=&quot;', ., '&quot;')), ' ')">
            <xsl:sort select="current-grouping-key()"/>
            <xsl:value-of select="concat(current-grouping-key(), '&#10;')"/>
          </xsl:for-each-group>
        </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 是的,我使用的是 XSLT 2.0 处理器。非常感谢您的帮助。我现在的输出是dictionaryentryform type"hyperlemma" xml:lang"cu"note type"editor's comment"orth。但是为什么form type"lemma" xml:lang"cu"form type"variant" xml:lang"cu"(相同的&lt;form&gt;元素,但属性名称不同)不在列表中?
    • 我已经重写了我的答案以使用for-each-group,因为我认为在 XSLT 2.0 的情况下这样做比使用密钥更好。我的第一个建议仅有助于输出那些由键标识的元素的属性值,但它并没有像您想要的那样尝试根据名称和属性名称和值来区分元素。可能需要进行一些排序才能获得您发布的输出。
    • 非常感谢您的(快速)帮助!感谢您的样式表,我现在得到了所需的输出。
    • 是的,如果输入有&lt;foo att1="value1" att2="value2"/&gt;&lt;foo att2="value2" att1="value1"/&gt;,我只想要一个元素输出。
    • 我添加了一个示例,按名称对属性进行排序。
    【解决方案2】:

    更简单的是使用distinct-values():

    <xsl:template match="/">
       <xsl:value-of select="distinct-values(//*/string-join(
                             (name(), @*/concat(name(), '=&quot;', ., '&quot;')), ' '))" 
               separator="&#10;"/>
    </xsl:template>
    

    【讨论】:

    • 非常感谢您提供另一个出色的解决方案!我没想到你可以用更少的代码行得到想要的输出......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-21
    • 2012-05-06
    • 1970-01-01
    • 2020-12-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多