2013-05-22 53 views
0

我有一个XML文档,其中包含有关父实体的用户定义信息。我想创建一个XSLT将XML转换为当前用户定义的列表。 XSLT将需要忽略已移除的元素,添加新元素并保留用户定义的元素顺序。使用XSLT添加和删除XML元素

例输入XML:

<InventoryProperties> 
     <InvProp Name="Weight" 
       Type="Text" 
       Alignment="Right">12500</InvProp> 
     <InvProp Name="Length" 
       Type="Text" 
       Alignemnt="Right">20.2</InvProp> 
     <InvProp Name="GVW" 
       Type="Text"></InvProp> 
    </InventoryProperties> 

所以,现在的用户已经改变了收集的数据点,并且不希望GVW了,但增加了身高体重和体长之间。什么到目前为止,我所做的就是这样来我想要的元素和离开我不再需要的元素背后:

<xsl:apply-templates select="InventoryProperties/InvProp[@Name = 'Weight']"/> 

重复的是当前定义的每个领域。这工作正常,并保持预期的顺序。对于加入新的元素,我想是这样的:

<xsl:apply-templates select="InventoryProperties[not(InvProp[@Name='Height'])]"/> 
<xsl:template name="HeightTemplate" 
       match="InventoryProperties[not(InvProp[@Name='Height'])]"> 

    <xsl:apply-templates select="@*[not(name()='Height')]|node()"/> 

    <Property LabelText="HelloWorld" /> 
    </xsl:template> 

而且这几个其他版本,但没有什么是生产什么,我想这将是:

<InventoryProperties> 
    <Property LabelText="Weight" 
      ControlType="Text">12500</Property> 
    <Property LabelText="Height" 
      ControlType="Text"></Property> 
    <Property LabelText="Length" 
      ControlType="Text">20.2</Property> 
</InventoryProperties> 

没有理由元素和属性名称的改变,我只是想分清什么是工作,什么不是。

+0

我不确定是否正确理解这一点。样式表(在你的例子中)应该忽略Name =“GVW”的元素,并在Name后面添加一个名称为“Height”的元素,如果它还没有一个呢? –

+0

@ hr_117 - 是的,这是正确的。在这个例子中,Xml是在最新定义之前保存的,所以当数据现在呈现给最终用户时,我们需要显示当前数据点,但不包括GVW,但是包括Height。 –

回答

0

我建议您为要添加到输出的每个字段名称调用一个命名模板。该命名模板将检查是否存在具有给定Name属性的元素,如果存在,则复制该元素,如果不是,则创建具有正确属性的存根。

这给出了这个概念

<xsl:template match="InventoryProperties"> 
    <xsl:call-template name="inv-prop"> 
    <xsl:with-param name="name" select="'Weight'"/> 
    </xsl:call-template> 
    <xsl:call-template name="inv-prop"> 
    <xsl:with-param name="name" select="'Height'"/> 
    </xsl:call-template> 
    <xsl:call-template name="inv-prop"> 
    <xsl:with-param name="name" select="'Length'"/> 
    </xsl:call-template> 
</xsl:template> 

<xsl:template name="inv-prop"> 
    <xsl:param name="name"/> 
    <xsl:variable name="selection" select="InvProp[@Name = $name]"/> 
    <xsl:choose> 
    <xsl:when test="$selection"> 
     <xsl:copy-of select="$selection"/> 
    </xsl:when> 
    <xsl:otherwise> 
     <InvProp Name="{$name}" Type="Text" Alignment="Right"> 
     <xsl:value-of select="InvProp[@Name = $name]"/> 
     </InvProp> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

输出

<?xml version="1.0" encoding="UTF-8"?> 
<root> 
    <InvProp Name="Weight" Type="Text" Alignment="Right">12500</InvProp> 
    <InvProp Name="Height" Type="Text" Alignment="Right"/> 
    <InvProp Name="Length" Type="Text" Alignemnt="Right">20.2</InvProp> 
</root> 
+0

有趣的是,我非常喜欢应用模板,我没有考虑过这种情况,唯一的缺点就是在这种情况下没有“存根”或默认值,每个属性的值对每个元素都是唯一的,为了简洁,我省略了几个属性。在你的例子中,你对Type和Alignment的值进行了硬编码,我不能这样做,我添加了更多的参数来传递其他参数价值观,这似乎工作,我很好奇尽管如此,鉴于我的新情况,你还会使用相同的解决方案吗? –

0

也许你应该试试这个。
身份转换与一些挂钩忽略或添加元素。

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

    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <!-- ingnore not wonted stuff --> 
    <xsl:template match ="InvProp[@Name='GVW'] " /> 

    <!-- add missing stuff --> 
    <xsl:template match ="InvProp[@Name='Weight'] "> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
     <xsl:if test="not(following-sibling::InvProp[@Name='Height'])" > 
      <InvProp Name="Height" Type="Text" Alignment="Right"/> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet>