2016-09-21 7 views
0

Я хотел бы открыть структуру набора данных XML, для которой я не вижу схемы XML. В рамках этого открытия я хотел бы вычислить минимальные и максимальные мощности (minOccurs и maxOccurs) элементов набора данных. Я пробовал различные инструменты для генерации XML-схем из документов XML, но они не генерируют minOccurs и maxOccurs. Тем не менее, я подозреваю, что это возможно с помощью XSLT (2.0+).XSLT для генерации мощностей элементов

Более конкретно, скажем, у меня есть следующий XML-документ:

<?xml version="1.0" encoding="UTF-8"?> 
<root> 
    <a/> 
    <b> 
     <c/> 
    </b> 
    <b/> 
</root> 

Я хотел бы быть в состоянии вычислить значения мощности в форме, как это:

<?xml version="1.0" encoding="UTF-8"?> 
<root> 
    <a minOccurs="1" maxOccurs="1"/> 
    <b minOccurs="2" maxOccurs="2"> 
     <c minOccurs="0" maxOccurs="1"/> 
    </b> 
</root> 

Дети корня будет всегда имеют одинаковую максимальную и минимальную мощность, поэтому часть может быть вычислена примерно так:

<xsl:template match="/*"> 
    <xsl:element name="{name()}"> 
     <xsl:for-each-group select="*" group-by="name()"> 
      <xsl:sort select="current-grouping-key()"/> 
      <xsl:element name="{current-grouping-key()}"> 
       <xsl:variable name="cardinality" select="count(current-group())"/> 
       <xsl:attribute name="minOccurs" select="$cardinality"/> 
       <xsl:attribute name="maxOccurs" select="$cardinality"/> 
      </xsl:element> 
     </xsl:for-each-group> 
    </xsl:element> 
</xsl:template> 

Однако я не могу окунуться в голову, как продолжить мощь внуков. Я подозреваю, что это можно абстрагировать в рекурсивный xsl:function.

Любые предложения о том, как действовать, приветствуются!

+0

"* Дети из корня всегда имеют одинаковую максимальную и минимальную мощность *« Почему? –

+0

Поскольку существует только один корневой элемент, его дочерние элементы будут иметь только одну мощность в одном документе XML. –

+0

> Я пробовал различные инструменты для генерации XML-схем из XML-документов. <Вы пытались использовать Oxygen -> generate XML? [Docu Oxygen] (https://www.oxygenxml.com/doc/versions/18.0/ug-editor /topics/converting-between-schema-languages.html) – uL1

ответ

3

Я не уверен, что 100%, если это подойдет вашим потребностям, но я придумал этот XSLT. Он работает путем группировки элементов по их именам пути (например, "корень/а/б")

<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 indent="yes"/> 

    <xsl:key name="parent_path" match="*" use="string-join(ancestor::*/name(), '/')" /> 
    <xsl:key name="full_path" match="*" use="string-join(ancestor-or-self::*/name(), '/')" /> 

    <xsl:template match="/*" priority="2"> 
     <xsl:element name="{name()}"> 
      <xsl:call-template name="element" /> 
     </xsl:element> 
    </xsl:template> 

    <xsl:template match="*" name="element"> 
     <xsl:variable name="path" select="string-join(ancestor-or-self::*/name(), '/')" /> 
     <xsl:for-each-group select="key('parent_path', $path)" group-by="name()"> 
      <xsl:sort select="current-grouping-key()"/> 
      <xsl:element name="{current-grouping-key()}"> 
       <xsl:variable name="counts" select="key('full_path', $path)/count(*[name() = name(current())])" /> 
       <xsl:variable name="min" select="min($counts)" /> 
       <xsl:variable name="max" select="max($counts)"/> 
       <xsl:attribute name="minOccurs" select="if (not(contains($path, '/'))) then $max else $min"/> 
       <xsl:attribute name="maxOccurs" select="$max"/> 
       <xsl:apply-templates select="." /> 
      </xsl:element> 
     </xsl:for-each-group> 
    </xsl:template> 
</xsl:stylesheet> 

При применении этого XML

<root> 
    <a/> 
    <b> 
     <c/> 
     <c/> 
    </b> 
    <b> 
     <c/> 
     <d> 
      <e /> 
     </d> 
     <g></g> 
     <g></g> 
     <g></g> 
    </b> 
    <b> 
     <c/> 
     <d> 
      <e /> 
      <e /> 
     </d> 
     <g></g> 
     <g></g> 
    </b> 
    <a/> 
</root> 

Ниже выводится ....

<root> 
    <a minOccurs="2" maxOccurs="2"/> 
    <b minOccurs="3" maxOccurs="3"> 
     <c minOccurs="1" maxOccurs="2"/> 
     <d minOccurs="0" maxOccurs="1"> 
     <e minOccurs="1" maxOccurs="2"/> 
     </d> 
     <g minOccurs="0" maxOccurs="3"/> 
    </b> 
</root> 
+0

Минимальная мощность не вычисляется правильно. Если я понимаю 'if (not (содержит ($ path, '/'))) th en $ cardinality else 0' правильно, тогда все элементы с родителем без корня будут иметь минимальный набор мощности 0, а остальные будут иметь одинаковую минимальную и максимальную мощность. –

+1

Извините, но я предпочел, чтобы элементы, отличные от root, всегда нуждались в minOccurs из 0. Однако я сделал настройку для своего ответа, поэтому теперь он должен рассчитать минимум на основе минимального количества дочерних элементов, а не считать 0 , –

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