2016-09-21 15 views
0

私はXMLスキーマがないXMLデータセットの構造を発見したいと思います。この発見の一環として、データセットの要素の最小および最大カーディナリティ(minOccursおよびmaxOccurs)を計算したいと思います。 XML文書からXMLスキーマを生成するためのさまざまなツールを試しましたが、minOccursmaxOccursは生成されません。しかし、私はXSLT(2.0+)でそうすることが可能であると思われます。要素カーディナリティを生成するXSLT

より具体的には、のは、私は次のXML文書を持っているとしましょう:

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

私はこのような形でカーディナリティを計算できるようにしたいと思います。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

ルート要素が1つしかないので、その子要素は単一のXML文書内にカーディナリティを1つだけ持ちます。 –

+0

> XML文書からXMLスキーマを生成するためのさまざまなツールを試しました XMLを生成しようとしましたか?[Docu Oxygen](https://www.oxygenxml.com/doc/versions/18.0/ug-editor /topics/converting-between-schema-languages.html) – uL1

答えて

3

これがあなたのニーズに合うかどうかわかりませんが、私はこのXSLTを考え出しました。この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> 

に適用する場合には、以下が出力....

ある

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

それらのパス名(例えば、 "ルート/ A/B")によって要素をグループ化することによって機能します

<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)を理解していれば、 (contains($ path、 '/')))番目のen $ cardinality else 0'を正しく指定すると、ルート以外の親を持つすべての要素の最小基数は0に設定されますが、他の要素は同じ最小値と最大基数を持ちます。 –

+1

申し訳ありませんが、ルート以外の要素には常に0のminOccursが必要であるという前提がありました。しかし、私は答えを微調整しましたので、0を仮定するのではなく、 。 –

関連する問題