【问题标题】:XSLT for extracting elements from a non linear XML structureXSLT 用于从非线性 XML 结构中提取元素
【发布时间】:2017-03-09 05:13:51
【问题描述】:

我有一个 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) 如果&lt;element2&gt; == 所有节点中的水果,我需要如下 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) 如果&lt;element2&gt; == 所有节点中的蔬菜,我需要如下 XML 模式

注意:&lt;element2&gt; == 蔬菜始终位于架构中的最后一个节点

<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 格式的任何帮助都会有很大帮助。

【问题讨论】:

  • 您的输入和输出都不是有效的 XML,因此无法使用 XML 工具进行处理。此外,您的条件语句 " if &lt;element2&gt; == fruits 在所有节点中,预期的 XML 将如下所示" 留下许多可能性,例如一些值是 fruits 和一些值是 vegetables。问题不清楚。
  • 仍然无效的 XML。例如&lt;element1&gt; 没有结束标签。
  • 你的(a)点是指fruits in all the nodes的情况。您的观点 (b) 是指vegetables in all the nodes 的情况。但是您的 XML 既有水果也有蔬菜,因此 (a) 和 (b) 点不适用。如果 XML 既有水果又有蔬菜,应该怎么办?您想要生成多个 XML 文档吗?还是应该在蔬菜之前与水果出现在相同的输出中?谢谢。
  • 为什么标签xslt-2.0 和 [libxslt] 用于同一个问题? Libxslt 仅支持 XSLT 1.0。
  • 嗨 @TimC 我需要 2 个 XML 输出文档来满足给定的 2 个条件,使用 2 个 XSLT。

标签: xslt xslt-2.0 xslt-grouping libxslt


【解决方案1】:

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

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

(这里'Fruits'只是默认值,如果调用应用程序没有指定参数)。

您将首先选择 element2 等于参数的节点(请注意 XML 和 XSLT 区分大小写,因此 element2 与您的 XML 中的 Element2 不同,但我假设这是您的 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>

【讨论】:

  • 我尝试了第一个 XSLT,但我看到一个错误 - ' Ambiguous rule match for /root 匹配第 12 行的“[element2]”和第 12 行的“/” 6 个 '
  • 我已经尝试了第二个 XSLT,但我看到一个错误 - ' Ambiguous rule match for /root 匹配第 14 行的“[element2]”和第 14 行的“/” 4 of '
  • 我已经更正了我的答案以处理冲突的模板。
  • 我现在看到以下错误'8:嵌套的应用模板调用太多。样式表可能正在循环。'
  • 我对我的答案进行了另一项更改,尽管听起来您的实际 XML 可能与您的问题中显示的有所不同。谢谢
猜你喜欢
  • 1970-01-01
  • 2012-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多