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

XSLT for extracting elements from a non linear XML structure

我有一个 XML 结构,其中 XML 模式是 irregular/not 格式的。结构看起来像这样-

<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> == fruits,我需要 XML 模式如下。我可以在 host -

下包含或排除以下 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 schema 如下

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

<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 格式的帮助都是很大的帮助。

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

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

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

您将从选择 element2 等于参数的节点开始(请注意 XML 并且 XSLT 区分大小写,因此 element2Element2 在您的 XML 中,但我认为这是您在 XML 中的错字。

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

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

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

其他节点将由标识模板处理。

试试这个 XSLT...

<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 2.0,则可以在一次调用中创建多个文档,使用 xsl:for-each-group 获取不同的组,并使用 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>