用于从非线性XML结构中提取元素的XSLT

时间:2017-03-09 05:13:52

标签: xslt xslt-2.0 xslt-grouping libxslt

我有一个XML结构,其中XML模式是不规则的/未格式化的。结构看起来像这样 -

<Host> 
<element1>type0</element1>
<element2>Fruits</element2>
....
<elementn>Price0</elementn>   
   <Menu>
   <NodeA>
    <element1>type1</element1>
    <element2>Fruits</element2>
    ....
    <elementn>Price1</elementn>
    <Menu>
    <NodeB>
      <element1>type2</element1>
      <element2>Fruits</element2>
      ....
      <elementn>Price2</elementn>
      <Menu>
      <NodeC>
        <element1>type3</element1>
        <element2>Fruits</element2>
        ....
        <elementn>Price3</elementn>
        <Menu>
        <NodeD>
          <Element1>type4</element1>
          <Element2>Vegetables</Element2>
          ....
          <Elementn>Price4</elementn>  
        </NodeD>
        </Menu>    
      </NodeC>
      </Menu>
     </NodeB>
     </Menu>
  </NodeA>
  <NodeE>
    <element1>type5</element1>
    <element2>Fruits</element2>
    ....
    <elementn>Price5</elementn>
    <Menu>
    <NodeF>
      <element1>type6</element1>
      <element2>Vegetables</element2>
      ....
      <elementn>Price6</elementn>
    </NodeF> 
    </Menu>  
  </NodeE>  
  </Menu> 
</Host>

现在我期望的XML如下 -

a)如果<element2> ==在所有节点中结果,我需要XML模式如下。我可以在主机下面包含或排除以下n个元素 -

`<element1>type0</element>
 <element2>Fruits</element2>
 ....
 <elementn>Price0</elementn>`

。预期结果 -

<Host> 
  <NodeA>
    <element1>type1</element1>
    <element2>Fruits</element2>
    ....
    <elementn>Price1</elementn>
  </NodeA>
  <NodeB>
    <element1>type2</element1>
    <element2>Fruits</element2>
    ....
    <elementn>Price2</elementn>
  </NodeB>
  <NodeC>
    <element1>type3</element1>
    <element2>Fruits</element2>
    ....
    <elementn>Price3</elementn>
  </NodeC>
  <NodeE>
    <element1>type5</element1>
    <element2>Fruits</element2>
    ....
    <elementn>Price5</elementn>
  </NodeE>    
</Host>

b)如果所有节点都有<element2> == vegetables,我需要XML模式如下

注意:<element2> ==蔬菜始终位于架构中的最后一个节点

<Host>
  <NodeD>
    <element1>type4</element1>
    <element2>Vegetables</element2>
    ....
    <elementn>Price4</elementn>
  </NodeD>    
  <NodeF>
    <element1>type6</element1>
    <element2>Vegetables</element2>
    ....
    <elementn>Price6</elementn>
  </NodeF>
</Host>

通过XSLT获取上述XML格式的任何帮助都将是一个很大的帮助。

1 个答案:

答案 0 :(得分:2)

如果您需要2个单独的文档,则实际上并不需要2个XSLT。您可以使用一个XSLT但使用参数

<xsl:param name="element2" select="'Fruits'" />

(此处'Fruits'只是默认值,如果调用应用程序未指定参数)。

您可以从选择element2等于参数的节点开始(请注意XML和XSLT区分大小写,因此element2Element2中的<xsl:apply-templates select="//*[element2=$element2]"/> 不同你的XML,但我认为这是你的XML中的拼写错误。)

<xsl:template match="*[element2]">
    <xsl:copy>
        <xsl:apply-templates select="*[not(*)]" />
    </xsl:copy>
</xsl:template>

您还需要一个模板来确保节点何时匹配,它不会复制子节点......

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes" />

    <xsl:param name="element2" select="'Fruits'" />

    <xsl:template match="/*">
        <xsl:copy>
            <xsl:apply-templates select="//*[element2=$element2]" mode="copy"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="*[element2]" mode="copy">
        <xsl:copy>
            <xsl:apply-templates select="*[not(*)]" mode="copy"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="@*|node()" mode="copy">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" mode="copy"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

其他节点将由身份模板处理。

试试这个XSLT ......

xsl:for-each-group

请注意,如果您使用的是XSLT 2.0,则可以在一次调用中创建多个文档,使用xsl:result-document获取不同的组,并<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml" indent="yes" /> <xsl:template match="/*"> <xsl:for-each-group select="//*[element2]" group-by="element2"> <xsl:result-document href="{current-grouping-key()}.xml" method="xml"> <Host> <xsl:apply-templates select="current-group()" mode="copy" /> </Host> </xsl:result-document> </xsl:for-each-group> </xsl:template> <xsl:template match="*[element2]" mode="copy"> <xsl:copy> <xsl:apply-templates select="*[not(*)]" mode="copy"/> </xsl:copy> </xsl:template> <xsl:template match="@*|node()" mode="copy"> <xsl:copy> <xsl:apply-templates select="@*|node()" mode="copy" /> </xsl:copy> </xsl:template> </xsl:stylesheet> 为每个文档创建一个文件。

try {
    sh './gradlew lint'
} finally {
    step([$class: 'ArtifactArchiver', artifacts: 'app/build/reports/staticAnalysis/lint/', fingerprint: true])
}