2016-09-21 102 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 。 –