如何仅使用命名空间从XML输入中复制或匹配选定的元素,然后同时删除命名空间

时间:2011-10-03 13:50:52

标签: xml xslt xml-namespaces

以下是我的XML输入。如何使用XSL复制或匹配我想在XML输出中反映的所选元素。

逻辑的一般思想应该是只指定我感兴趣的元素,而不是指定我不喜欢包含在输出中的元素。我希望在输出XML中反映的元素始终存在于XML Inpput中。其余元素根据系统生成的内容而有所不同,因此我不能只指定要删除的内容。

通过执行复制,我能够从输入中没有命名空间,但是当命名空间存在时,代码无效。

我找到了一种删除命名空间的方法,但是当与副本结合使用时,也无法正常工作。我对XSL的行为方式感到很困惑。

请接受我的询问,我是XML和XSL的新手,我被分配到这个任务,因为我们团队中没有人有使用XML的经验。提前谢谢。

XML输入:

<Transaction xmlns="http://www.test.com/rdc.xsd">
    <Transaction>
        <StoreName id="aa">STORE A</StoreName>
        <TransNo>TXN0001</TransNo>
        <RegisterNo>REG001</RegisterNo>
        <Items>
            <Item id="1">
                <ItemID>A001</ItemID>
                <ItemDesc>Keychain</ItemDesc>
            </Item>
            <Item id="2">
                <ItemID>A002</ItemID>
                <ItemDesc>Wallet</ItemDesc>
            </Item>
        </Items>
        <IDONTLIKETHIS_1>
            <STOREXXX>XXX</STOREXXX>
            <TRANSXXX>YYY</TRANSXXX>
        </IDONTLIKETHIS_1>
        <IDONTLIKETHIS_2>
            <STOREXXX>XXX</STOREXXX>
            <TRANSXXX>YYY</TRANSXXX>
        </IDONTLIKETHIS_2>
    </Transaction>
</Transaction>

期望的输出:

<Transaction>
    <Transaction>
        <StoreName id="aa">STORE A</StoreName>
        <TransNo>TXN0001</TransNo>
        <RegisterNo>REG001</RegisterNo>
        <Items>
            <Item id="1">
                <ItemID>A001</ItemID>
                <ItemDesc>Keychain</ItemDesc>
            </Item>
            <Item id="2">
                <ItemID>A002</ItemID>
                <ItemDesc>Wallet</ItemDesc>
            </Item>
        </Items>
    </Transaction>
</Transaction>

我已经尝试了下面的代码,但问题是我缺少第二个Transaction元素,xmlns属性出现在根元素中:

<xsl:template match="*">
  <xsl:copy-of select="@*"/>
  <xsl:apply-templates/>
</xsl:template>
<xsl:template match="node()[not(self::*)]">
  <xsl:copy-of select="."/>      
</xsl:template>   
<xsl:template match="*">
  <xsl:copy>
      <xsl:copy-of select="x:Transaction/x:StoreName"/>
      <xsl:copy-of select="x:Transaction/x:TransNo"/>
      <xsl:copy-of select="x:Transaction/x:RegisterNo"/>
      <xsl:copy-of select="x:Transaction/x:Items"/>
 </xsl:copy>      
</xsl:template>

3 个答案:

答案 0 :(得分:2)

此转换使用我们要在处理后复制的所有元素名称列表

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:x="http://invia.fujitsu.com/RetailDATACenter/rdc.xsd">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:param name="pNames" select=
    "'|Transaction|StoreName|TransNo|RegisterNo|Items|Item|ItemID|ItemDesc'"/>

    <xsl:template match="*" >
     <xsl:if test=
      "contains($pNames,
                concat('|',local-name(), '|')
              )">
        <xsl:element name="{name()}">
            <xsl:copy-of select="@*"/>
            <xsl:apply-templates select="node()"/>
        </xsl:element>
     </xsl:if>
    </xsl:template>

    <xsl:template match="node()[not(self::*)]">
        <xsl:copy-of select="."/>
    </xsl:template>
</xsl:stylesheet>

应用于提供的XML文档

<Transaction xmlns="http://www.test.com/rdc.xsd">
    <Transaction>
        <StoreName id="aa">STORE A</StoreName>
        <TransNo>TXN0001</TransNo>
        <RegisterNo>REG001</RegisterNo>
        <Items>
            <Item id="1">
                <ItemID>A001</ItemID>
                <ItemDesc>Keychain</ItemDesc>
            </Item>
            <Item id="2">
                <ItemID>A002</ItemID>
                <ItemDesc>Wallet</ItemDesc>
            </Item>
        </Items>
        <IDONTLIKETHIS_1>
            <STOREXXX>XXX</STOREXXX>
            <TRANSXXX>YYY</TRANSXXX>
        </IDONTLIKETHIS_1>
        <IDONTLIKETHIS_2>
            <STOREXXX>XXX</STOREXXX>
            <TRANSXXX>YYY</TRANSXXX>
        </IDONTLIKETHIS_2>
    </Transaction>
</Transaction>

产生了想要的正确结果:

<Transaction>
   <Transaction>
      <StoreName id="aa">STORE A</StoreName>
      <TransNo>TXN0001</TransNo>
      <RegisterNo>REG001</RegisterNo>
      <Items>
         <Item id="1">
            <ItemID>A001</ItemID>
         </Item>
         <Item id="2">
            <ItemID>A002</ItemID>
         </Item>
      </Items>
   </Transaction>
</Transaction>

请注意:此解决方案优于其他可能解决方案的一个优点是,包含管道分隔的元素名称列表的字符串可以作为外部指定的参数提供给转换,非常强大和灵活,无需在我们的白名单中包含新元素(或排除某些元素)时更改代码。

答案 1 :(得分:1)

这会有用吗?

<xsl:stylesheet
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  version="2.0">
  <xsl:variable name="allowed">
    <names>
      <name>Transaction</name>
      <name>StoreName</name>
      <name>TransNo</name>
      <name>RegisterNo</name>
      <name>Items</name>
      <name>Item</name>
      <name>ItemID</name>
      <name>ItemDesc</name>
      <name>id</name>
    </names>
  </xsl:variable>
  <xsl:template match="text()">
    <xsl:copy-of select="."/>
  </xsl:template>
  <xsl:template match="@*">
    <xsl:copy-of select="."/>
  </xsl:template>
  <xsl:template match="comment()">
    <xsl:copy-of select="."/>
  </xsl:template>
  <xsl:template match="processing-instruction()">
    <xsl:copy-of select="."/>
  </xsl:template>
  <xsl:template match="*">
    <xsl:if test="local-name(.) = $allowed//name">
      <xsl:element name="{local-name(.)}">
        <xsl:apply-templates select="@*"/>
        <xsl:apply-templates select="node()"/>
      </xsl:element>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>

答案 2 :(得分:1)

这似乎可以满足您的需求,但请阅读命名空间,因为我不确定您打算做什么是明智的。

希望这有帮助,

<xsl:stylesheet version="1.0" xmlns:abc="http://www.test.com/rdc.xsd" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="abc:Transaction|abc:StoreName|abc:TransNo|abc:RegisterNo|abc:Items|abc:Item|abc:ItemID|abc:ItemDesc">
    <xsl:element name="{local-name()}"> 
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates/>
    </xsl:element>
</xsl:template>

<xsl:template match="@*"> 
    <xsl:copy/> 
</xsl:template> 

<xsl:template match="*"/>


</xsl:stylesheet>