2

精简版:

任何人都可以在 LINQ to XML for VB 或 XSLT 中建议或提供一个示例,说明如何将一个 XML 元素更改为另一个(无需硬编码所有未更改元素的逐个元素副本)?

背景:

我有一个我认为格式正确的 XML 文件,其中包含一个根条目<collection> 和多个<dvd> 元素。在 DVD 中,有流派和标签,如下所示。(为简单起见,我删去了很多其他元素)。

我想要做的是将任何<Tag可能存在的 > 元素变成一个额外的<Genre>。例如,在下面的条目中,我需要添加<Genre>Kids </Genre>。(我意识到它实际上是 TAG 元素的 NAME 属性,我希望将其转换为 GENRE 元素,但如果我什至可以弄清楚如何创建一个名为“Tag”的新 GENRE,我会走得更远并且可能会解开其余的问题。)

我从来没有对 XML 做过很多事情。我的理解是,我可以使用 XSLT 转换文件和 XSLCompiledTransform,或者我可以使用 LINQ to XML(我有 Visual Basic 9,并且更愿意在 VB 中完成这一切)。[我相信还有许多其他方法。]

麻烦的是,我找不到任何 XSLT 或 LINQ 语法示例来告诉我如何将一个元素转换为另一个元素。我可以写出足够多的 LINQ 来一个一个地复制所有元素,但是必须有一种比硬编码所有不变元素的副本更简单的方法!(必须有!)

因此,如果知道的人可以为我提供一个示例或帮助我了解一些 LINQ 或 XSLT 中的入门代码,我将永远感激不尽(好吧,也许不是永远,但至少在很长一段时间内!)。

谢谢。

示例 XML:

<Collection>
  <DVD>
    <ID>0000502461</ID>
    <Title>Cirque du Soleil: Alegría</Title>
    <Released>2002-05-31</Released>
    <RunningTime>90</RunningTime>
    <Genres>
      <Genre>Family</Genre>
      <Genre>Music</Genre>
    </Genres>
    <Overview>What if anything were possible? What if ...
    </Overview>
    <Notes/>
    <Tags>
      <Tag Name="Kids" FullName="Kids"/>
    </Tags>
  </DVD>
</Collection>
4

4 回答 4

2

使用最基本和最强大的 XSLT 设计模式之一:覆盖标识模板,人们将编写这个非常简单的转换来用“主题”元素替换每个“流派”元素:

<xsl:stylesheet 版本="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:输出省略-xml-declaration="yes"/>

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

    <xsl:template match="流派">
      <主题>
         <xsl:apply-templates select="node()|@*"/>
      </主题>
    </xsl:模板>
</xsl:样式表>

针对提供的源 XML 文档应用时:

<收藏>
    <DVD>
        <ID>0000502461</ID>
        <Title>太阳马戏团:Alegría</Title>
        <发布>2002-05-31</发布>
        <RunningTime>90</RunningTime>
        <体裁>
            <体裁>家庭</体裁>
            <流派>音乐</流派>
        </流派>
        <Overview>如果一切皆有可能呢?如果... </Overview>
        <注意事项/>
        <标签>
            <Tag Name="Kids" FullName="Kids"/>
        </标签>
    </DVD>
</收藏>

产生了想要的结果:

<收藏>
    <DVD>
        <ID>0000502461</ID>
        <Title>太阳马戏团:Alegría</Title>
        <发布>2002-05-31</发布>
        <RunningTime>90</RunningTime>
        <主题>
            <体裁>家庭</体裁>
            <流派>音乐</流派>
        </主题>
        <Overview>如果一切皆有可能呢?如果... </Overview>
        <注意事项/>
        <标签>
            <Tag Name="Kids" FullName="Kids"/>
        </标签>
    </DVD>
</收藏>

样式表中的第一个模板是身份规则。它复制任何匹配的节点,并以递归方式将模板应用于其属性或子节点。如果不存在其他模板,则此模板会创建与源 xml 文档相同的副本,因此得名。

当有更具体的模板(为匹配的节点指定更具体的细节,例如名称和/或其他条件)时,称为“覆盖”更通用的模板。这意味着选择更具体的模板来处理节点。

使用这种极其强大的设计模式,只需几行代码就可以轻松实现以下处理:

  1. 删除所有满足某个条件的节点。
  2. 重命名满足某些条件的所有节点。
  3. 修改所有满足某个条件的节点的内容

同时完整地复制所有其他节点。

在我们的例子中,第二个模板更具体,它被选中用于处​​理每个名为“流派”的元素。它所做的只是创建一个名为“Topics”的元素,并在其中将模板应用于所有当前节点属性和子节点。

最后以下转换将为每个“标签”元素添加一个新的“流派”元素到“流派”的子元素

<xsl:stylesheet 版本="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

 <xsl:输出省略-xml-declaration="yes"/>

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

    <xsl:template match="流派">
      <xsl:复制>
         <xsl:apply-templates select="node()|@*"/>
         <xsl:apply-templates select="../Tags/Tag" mode="Gen"/>
      </xsl:copy>
    </xsl:模板>

    <xsl:template match="Tag" mode="Gen">
      <类型>
        <xsl:value-of select="@Name"/>
      </体裁>
    </xsl:模板>
</xsl:样式表>

结果再次符合要求:

<收藏>
    <DVD>
        <ID>0000502461</ID>
        <Title>太阳马戏团:Alegría</Title>
        <发布>2002-05-31</发布>
        <RunningTime>90</RunningTime>
        <体裁>
            <体裁>家庭</体裁>
            <流派>音乐</流派>
        <Genre>Kids</Genre>
        </流派>
        <Overview>如果一切皆有可能呢?如果... </Overview>
        <注意事项/>
        <标签>
            <Tag Name="Kids" FullName="Kids"/>
        </标签>
    </DVD>
</收藏>

更多使用“身份规则”模式的代码片段可以在这里找到。

于 2008-11-26T23:55:00.250 回答
1

您可以将任何节点与 匹配node(),如下所示:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<!-- Uncomment to remove Tags elements -->
<!-- <xsl:template match="Tags" /> -->

<xsl:template match="Genres">
    <xsl:copy>
        <xsl:apply-templates select="@*|node()" />
        <xsl:for-each select="../Tags/Tag">
            <xsl:element name="Genre">
                <xsl:value-of select="@Name" />
            </xsl:element>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

<!-- Default rule: Copy node and descend -->
<xsl:template match="@*|node()">
        <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
</xsl:template>

</xsl:stylesheet>
于 2008-11-26T23:25:01.900 回答
0

您是否正在寻找这样的东西:

 <xsl:template match="Tag">
    <xsl:element name="Genre">
      <xsl:value-of select="@Name"/>           
    </xsl:element>    
  </xsl:template>
于 2008-11-26T23:24:31.793 回答
0

我在 VB9 中也有同样的需求,想使用 Linq 而不是 XSL。我发现了这个:http: //msdn.microsoft.com/en-us/library/bb669154.aspx,它工作得非常好。

于 2009-09-05T17:37:51.163 回答