2014-11-26 2 views
1

Я хотел бы «сканировать» мои xml-файлы с помощью xslt и получить список отдельных имен элементов , а также имена их атрибутов.Как получить список имен отдельных элементов плюс их имена атрибутов с помощью XSLT

Мой 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 

Как это достичь?

ответ

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" 

для меня Saxon 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 

Я думаю, чтобы получить согласованный результат, код будет также первой необходимости сортировать атрибуты по имени, поскольку я подозреваю, что на входе есть <foo att1="value1" att2="value2"/> и <foo att2="value2" att1="value1"/>, что вам нужен только один элемент.

, что сортировка может быть выполнена с

<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> 
+0

Да, я использую XSLT процессор 2.0. Большое спасибо за Вашу помощь. Теперь мой вывод - 'dictionary',' entry', 'form type" hyperlemma "xml: lang" cu ",' note type "комментарий редактора" ',' orth'. Но почему «форма типа« лемма »xml: lang« cu »и« form type »вариант« xml: lang «cu» '(тот же элемент'

', но другое имя атрибута) нет в списке? – smo

+0

Я переписал свой ответ, чтобы использовать 'for-each-group', поскольку я думаю, что лучше делать это в случае XSLT 2.0 вместо использования ключа. Мое первое предложение помогло выводить значения атрибутов для тех элементов, которые идентифицировал ключ, но он не пытался отличать элементы, основанные на именах и именах имен и значениях, как вы, кажется, хотите сделать. Возможно, будет некоторая сортировка, чтобы сделать вывод, когда вы разместили сообщение. –

+0

Большое вам спасибо за вашу (быструю) помощь! Благодаря вашей таблице стилей я получаю желаемый результат. – smo

1

Даже проще заключается в использовании distinct-values():

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

Большое спасибо за отличное решение! Я бы не подумал, что вы можете получить желаемый результат с еще меньшим количеством строк кода ... – smo

Смежные вопросы