2016-09-21 103 views
0

我想發現一個XML數據集的結構,對此我沒有XML模式。作爲此發現的一部分,我想計算數據集元素的最小和最大基數(minOccursmaxOccurs)。我已經嘗試過從XML文檔生成XML模式的各種工具,但它們不生成minOccursmaxOccurs。不過,我懷疑這樣做對於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模式的各種工具<您嘗試過了「氧氣 - >生成XML嗎?[Docu Oxygen](https://www.oxygenxml.com/doc/versions/18.0/ug-editor /topics/converting-between-schema-languages.html) – uL1

回答

3

我不確定100%是否適合您的需求,但我想出了這個XSLT。它的工作原理通過分組通過路徑名稱的元素(例如, 「根/ A/B」)

<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 (包含($ path,'/')))th en $ cardinality else 0',那麼所有具有非根父元素的元素將具有最小基數0,而其他元素將具有相同的最小和最大基數。 –

+1

對不起,我做了比非根元素總是需要minOccurs爲0的假設。但是,我已經對我的答案進行了調整,所以現在它應該根據子元素的最小數量計算最小值,而不是假設0 。 –