XSLT从以下类型的XML结构中删除除特定节点之外的所有节点

时间:2012-11-12 15:09:59

标签: xml xslt

<Rootnode>
    <Properties Attribute ="xxx">
        <Type>1</Type>
        <Size>10</Size>
    </Properties>
    <Other>
        <blah>h</blah>
    </Other>
    <Other2>
        <blah>h</blah>
    </Other2>
    <Properties Attribute ="xxx">
        <xType>5</xType>
        <xSize>10</xSize>
    </Properties>
    <Items>
       <Item4>8</Item4>
    </Items>
    <Items>
       <Item6>8</Item6>
    </Items>
    <Properties Attribute ="xxx">
        <zType>1</zType>
        <zSize>10</zSize>
    </Properties>
    <Items place="UK">
       <Item1>8</Item1>
    </Items>
 </Rootnode>

现在我想要的只是包含属性和项目。如果属性具有相同的名称和值,则最好将Properties和Items组连接在一起,并根据Attributes SORT Properties和Items,并按字母顺序对子节点进行排序。 到目前为止,我已经空白了;(

所需的输出几乎与ABach所示相同。虽然我忘了提到的一件事是每个属性或项目上可能有其他属性,我知道我想要排序的属性的名称。我可以很容易地修改。

即所需的输出

<?xml version="1.0"?>
<Rootnode>
  <Properties Attribute="xxx">
    <Size>10</Size>
    <Type>1</Type>
    <xSize>10</xSize>
    <xType>5</xType>
    <zSize>10</zSize>
    <zType>1</zType>
  </Properties>
  <Items>
    <Item4>8</Item4>
    <Item6>8</Item6>
  </Items>
  <Items place="UK">
    <Item1>8</Item1>
  </Items>
</Rootnode>

对于到目前为止我没有努力而道歉...我最终陷入了混乱,并且认为它不会有太多帮助......我对这些东西很新:)

2 个答案:

答案 0 :(得分:2)

正如@LarsH已经指出的那样,通过不向我们展示预期的输出XML,我们只能猜测你真正想要的东西。也就是说,这是我尝试使用XSLT 1.0解决方案。

当这个XSLT:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
  <xsl:output omit-xml-declaration="no" indent="yes" />
  <xsl:strip-space elements="*" />

  <xsl:key
    name="PropertiesByAttributeNameVal"
    match="Properties"
    use="concat(name(@*[1]), '+', @*[1])" />

  <xsl:key
    name="ItemsByAttributeNameVal" 
    match="Items"
    use="concat(name(@*[1]), '+', @*[1])" />

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

  <xsl:template match="Rootnode">
    <Rootnode>
      <xsl:apply-templates 
        select="Properties[
          generate-id() = 
          generate-id(key(
            'PropertiesByAttributeNameVal',
             concat(name(@*[1]), '+', @*[1]))[1])]">
        <xsl:with-param name="pKeyName"
          select="'PropertiesByAttributeNameVal'" />
        <xsl:sort select="concat(name(@*[1]), '+', @*[1])" />
      </xsl:apply-templates>
      <xsl:apply-templates
        select="Items[
          generate-id() = 
          generate-id(key(
            'ItemsByAttributeNameVal',
            concat(name(@*[1]), '+', @*[1]))[1])]">
        <xsl:with-param name="pKeyName"
          select="'ItemsByAttributeNameVal'" />
        <xsl:sort select="concat(name(@*[1]), '+', @*[1])" />
      </xsl:apply-templates>
    </Rootnode>
  </xsl:template>

  <xsl:template match="Properties|Items">
    <xsl:param name="pKeyName" />
    <xsl:copy>
      <xsl:apply-templates select="@*" />
      <xsl:apply-templates
        select="key($pKeyName, concat(name(@*[1]), '+', @*[1]))/*">
        <xsl:sort select="name()" />
      </xsl:apply-templates>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

...针对提供的XML运行:

<Rootnode>
  <Properties Attribute="xxx">
    <Type>1</Type>
    <Size>10</Size>
  </Properties>
  <Other>
    <blah>h</blah>
  </Other>
  <Other2>
    <blah>h</blah>
  </Other2>
  <Properties Attribute="xxx">
    <xType>5</xType>
    <xSize>10</xSize>
  </Properties>
  <Items>
    <Item4>8</Item4>
  </Items>
  <Items>
    <Item6>8</Item6>
  </Items>
  <Properties Attribute="xxx">
    <zType>1</zType>
    <zSize>10</zSize>
  </Properties>
  <Items place="UK">
    <Item1>8</Item1>
  </Items>
</Rootnode>

...我猜是正确的输出XML是生成的:

<?xml version="1.0"?>
<Rootnode>
  <Properties Attribute="xxx">
    <Size>10</Size>
    <Type>1</Type>
    <xSize>10</xSize>
    <xType>5</xType>
    <zSize>10</zSize>
    <zType>1</zType>
  </Properties>
  <Items>
    <Item4>8</Item4>
    <Item6>8</Item6>
  </Items>
  <Items place="UK">
    <Item1>8</Item1>
  </Items>
</Rootnode>

请注意,如果针对略微修改的XML文档(具有更多分组等)运行相同的XSLT:

<?xml version="1.0" encoding="utf-8"?>
<Rootnode>
  <Properties Attribute="xxx">
    <Type>1</Type>
    <Size>10</Size>
  </Properties>
  <Other>
    <blah>h</blah>
  </Other>
  <Other2>
    <blah>h</blah>
  </Other2>
  <Properties Attribute="yyy">
    <xType>5</xType>
    <xSize>10</xSize>
  </Properties>
  <Items>
    <Item4>8</Item4>
  </Items>
  <Items place="US">
    <Item9>8</Item9>
  </Items>
  <Items>
    <Item1>8</Item1>
  </Items>
  <Properties Attribute2="xxx">
    <zType>1</zType>
    <zSize>10</zSize>
  </Properties>
  <Properties Attribute="xxx">
    <elephantType>5</elephantType>
    <elephantSize>15</elephantSize>
  </Properties>
  <Items place="UK">
    <Item1>8</Item1>
  </Items>
</Rootnode>

...再次,我假设正确答案产生了:

<?xml version="1.0"?>
<Rootnode>
  <Properties Attribute="xxx">
    <Size>10</Size>
    <Type>1</Type>
    <elephantSize>15</elephantSize>
    <elephantType>5</elephantType>
  </Properties>
  <Properties Attribute="yyy">
    <xSize>10</xSize>
    <xType>5</xType>
  </Properties>
  <Properties Attribute2="xxx">
    <zSize>10</zSize>
    <zType>1</zType>
  </Properties>
  <Items>
    <Item1>8</Item1>
    <Item4>8</Item4>
  </Items>
  <Items place="UK">
    <Item1>8</Item1>
  </Items>
  <Items place="US">
    <Item9>8</Item9>
  </Items>
</Rootnode>

<强>假设:

  • 我假设每个<Properties><Items>元素只有一个属性,它应该是分组限定符。
  • 如果上述情况不属实,我至少假设该元素的第一个属性应该是分组确定器。

<强>解释

  1. 因为这是一个XSLT 1.0解决方案,Muenchian Grouping是在唯一选择器下对节点和属性进行分组时的顺序。因此,我们定义了两个键:一个用于<Properties>元素,另一个用于<Items>元素。

  2. 第一个模板是Identity Transform - 它的工作是按原样将源文档中的所有节点和属性输出到结果文档。

  3. 第二个模板与<Rootnode>元素匹配。系统会指示仅将模板应用于首先出现在各自键中的<Properties><Items>元素;这具有仅处理唯一元素的预期效果(基于其第一个属性的名称和值)。

    当指定<xsl:apply-templates>元素时,请注意在两个实例中,都指示按相同的属性名称/值配对对结果进行排序。

    请注意,每个<xsl:apply-templates>元素都有一个参数(通过<xsl:with-param>)。如您所见,处理<Properties><Items>元素的代码几乎相同;唯一的区别是我们从中获取结果的关键。因此,我选择将该逻辑合并到第三个模板中,并通过此参数考虑可变性。

  4. 第三个模板与<Properties><Items>元素相匹配。对于每个,复制原始节点(其属性也是如此)。最后,模板应用于此元素的所有子元素(发生适当的排序[此次,基于子元素本身的名称])。

答案 1 :(得分:1)

如果你已经拥有某些东西而不是什么,那么你将更有可能获得帮助。首先,创建一个与属性和项目(match="Properties | Items")匹配的模板,其内容只复制匹配的元素:<xsl:copy-of select="." />

这将为您提供一些可用的代码。

我建议的下一步是发布所需输出的样本,以及XSLT代码给出的实际输出。

这将为人们回答你的问题提供一个更小的差距。