首页 文章

如何复制xml元素

提问于
浏览
6

我必须根据特定的id(例如userid)将xml有效负载复制到尽可能多的xml有效负载中

<ns2:Details xmlns:ns2="ns">
  <ns2:var1>AA0511201143</ns2:var1>
  <ns2:var2>PARCEL</ns2:var2>
  <ns2:var3>04/04/2011</ns2:var3>
  <ns2:var4>Organization</ns2:var4>
  <ns2:UserId>46</ns2:UserId>
  <ns2:UserId>237</ns2:UserId>
</ns2:Details>

我需要输出为

<ns2:Details>
  <ns2:var1>AA0511201143</ns2:var1>
  <ns2:var2>PARCEL</ns2:var2>
  <ns2:var3>04/04/2011</ns2:var3>
  <ns2:var4>Organization</ns2:var4>
  <ns2:UserId>46</ns2:UserId>
</ns2:Details>
<ns2:Details>
  <ns2:var1>AA0511201143</ns2:var1>
  <ns2:var2>PARCEL</ns2:var2>
  <ns2:var3>04/04/2011</ns2:var3>
  <ns2:var4>Organization</ns2:var4>
  <ns2:UserId>237</ns2:UserId>
</ns2:Details>

这可能吗


Update: 给出的以下答案工作正常,但重复's a small catch I failed to mention. If the userid is the same and it',则应显示相同的xml有效负载 . 为此,我尝试了以下方法来获取userid的独特元素

<xsl:param name="userId" select="ns0:UserId[generate-id(.)=generate-id(key('k', ns0:UserId)[1])]"/>

但这不起作用,也尝试使用上面

..[generate-id(.)=generate-id(key('k', ns0:UserId)[1])]

在模板级别它也无法正常工作

我错过了什么吗?

Update :我对上面的代码做了一个小修改,而不是在xsl:param上工作,我在xsl上使用了它:apply-template

在修改之前(作为对我的回答)修改后的<xsl:apply-templates select =“// ns2:Details / ns2:UserId”/> <xsl:apply-templates select =“// ns2:Details / ns2:UserId [generate-id( . )= generate-id(key('myUserId', . )[1])]“/>

我的错误是使用ns2:userid而不是“ . ”

完整的xsl代码---

<xsl:output method="xml" indent="yes"/>
<xsl:key name="k" match="ns2:UserId" use="text()"/>
<xsl:key name="myUserId" match="ns2:UserId" use="."/>
  <xsl:template match="/">
    <ns2:Root>
            <xsl:apply-templates select="//ns2:Details/ns2:UserId[generate-id(.)=generate-id(key('myUserId', .)[1])]"/>
    </ns2:Root>
  </xsl:template> 

 <xsl:template match="//ns2:Details">
    <xsl:param name="userId" select="ns2:UserId"/>
    <ns2:Details>
      <xsl:copy-of select="key('k', $userId)[1]"/>  <!-- displays UserId values-->
      <xsl:copy-of select="./*[name() != 'ns2:UserId']"/> <!-- displays other values-->
    </ns2:Details>
  </xsl:template> 

 <xsl:template match="ns2:UserId">
    <xsl:apply-templates select="..">
      <xsl:with-param name="userId" select="."/>
    </xsl:apply-templates>
  </xsl:template>

请验证它 . 这也对我有用......

7 回答

  • 0

    假设的XML:

    <ns2:Details xmlns:ns2="ns2">
      <ns2:var1>AA0511201143</ns2:var1>
      <ns2:var2>PARCEL</ns2:var2>
      <ns2:var3>04/04/2011</ns2:var3>
      <ns2:var4>Organization</ns2:var4>
      <ns2:UserId>46</ns2:UserId>
      <ns2:UserId>237</ns2:UserId>
      <ns2:UserId>46</ns2:UserId>
    </ns2:Details>
    

    XSLT:

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      xmlns:ns2="ns2"
    >
      <xsl:output method="xml" indent="yes"/>
    
      <xsl:key name="k" match="ns2:UserId" use="text()"/>
    
      <xsl:template match="/">
        <root>
          <xsl:apply-templates select="//ns2:Details/ns2:UserId[not(node() = preceding-sibling::node())]"/>
        </root>
      </xsl:template>
    
      <xsl:template match="//ns2:Details">
        <xsl:param name="userId" select="ns2:UserId"/>
    
        <ns2:Details>
          <xsl:copy-of select="key('k', $userId)[not(node() = preceding-sibling::node())]"/>
          <xsl:copy-of select="./*[name() != 'ns2:UserId']"/>
        </ns2:Details>
      </xsl:template>
    
      <xsl:template match="ns2:UserId">
        <xsl:apply-templates select="..">
          <xsl:with-param name="userId" select="."/>
        </xsl:apply-templates>
      </xsl:template>
    
    </xsl:stylesheet>
    

    输出XML:

    <?xml version="1.0" encoding="utf-8"?>
    <root xmlns:ns2="ns2">
      <ns2:Details>
        <ns2:UserId>46</ns2:UserId>
        <ns2:var1>AA0511201143</ns2:var1>
        <ns2:var2>PARCEL</ns2:var2>
        <ns2:var3>04/04/2011</ns2:var3>
        <ns2:var4>Organization</ns2:var4>
      </ns2:Details>
      <ns2:Details>
        <ns2:UserId>237</ns2:UserId>
        <ns2:var1>AA0511201143</ns2:var1>
        <ns2:var2>PARCEL</ns2:var2>
        <ns2:var3>04/04/2011</ns2:var3>
        <ns2:var4>Organization</ns2:var4>
      </ns2:Details>
    </root>
    
  • 0

    This transformation (简称,只有两个模板,没有 xsl:for-each ,没有模式):

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns2="ns">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:key name="kIdByVal" match="ns2:UserId" use="."/>
    
     <xsl:template match="/">
      <xsl:apply-templates select=
      "ns2:Details/ns2:UserId
            [generate-id()=generate-id(key('kIdByVal',.)[1])]
      "/>
     </xsl:template>
    
     <xsl:template match="ns2:UserId">
      <ns2:Details>
       <xsl:copy-of select=
        "../node()
              [not(self::ns2:UserId
                     [not(generate-id()=generate-id(current()))])
              ]"/>
      </ns2:Details>
     </xsl:template>
    </xsl:stylesheet>
    

    when applied on this XML document (包含冗余的 ns2:UserId 元素):

    <ns2:Details xmlns:ns2="ns">
        <ns2:var1>AA0511201143</ns2:var1>
        <ns2:var2>PARCEL</ns2:var2>
        <ns2:var3>04/04/2011</ns2:var3>
        <ns2:var4>Organization</ns2:var4>
        <ns2:UserId>46</ns2:UserId>
        <ns2:UserId>237</ns2:UserId>
        <ns2:UserId>46</ns2:UserId>
    </ns2:Details>
    

    produces exactly the wanted, correct result

    <ns2:Details xmlns:ns2="ns">
       <ns2:var1>AA0511201143</ns2:var1>
       <ns2:var2>PARCEL</ns2:var2>
       <ns2:var3>04/04/2011</ns2:var3>
       <ns2:var4>Organization</ns2:var4>
       <ns2:UserId>46</ns2:UserId>
    </ns2:Details>
    <ns2:Details xmlns:ns2="ns">
       <ns2:var1>AA0511201143</ns2:var1>
       <ns2:var2>PARCEL</ns2:var2>
       <ns2:var3>04/04/2011</ns2:var3>
       <ns2:var4>Organization</ns2:var4>
       <ns2:UserId>237</ns2:UserId>
    </ns2:Details>
    

    Explanation :Muenchian分组, xsl:copy-of ,使用 current()

  • 0

    对的,这是可能的 . 您可以使用for-each ns2:UserID节点使用for-each loop进行循环 .

  • 1

    以下样式表处理重复项:

    <xsl:stylesheet version="1.0" 
                    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                    xmlns:ns2="ns2">
        <xsl:output method="xml" indent="yes" />
        <xsl:key name="byUserId" match="ns2:UserId" use="." />
        <xsl:template match="/">
            <root>
                <xsl:apply-templates
                    select="ns2:Details/ns2:UserId
                        [generate-id()=generate-id(key('byUserId', .)[1])]" />
            </root>
        </xsl:template>
        <xsl:template match="ns2:UserId">
            <xsl:apply-templates select=".." mode="out">
                <xsl:with-param name="userId" select="." />
            </xsl:apply-templates>
        </xsl:template>
        <xsl:template match="ns2:Details" mode="out">
            <xsl:param name="userId" select="''" />
            <xsl:copy>
                <xsl:apply-templates select="node()|@*" mode="out" />
                <xsl:copy-of select="$userId"/>
            </xsl:copy>
        </xsl:template>
        <xsl:template match="ns2:UserId" mode="out" />
        <xsl:template match="node()|@*" mode="out">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*" mode="out" />
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    

    在此输入:

    <ns2:Details xmlns:ns2="ns2">
        <ns2:var1>AA0511201143</ns2:var1>
        <ns2:var2>PARCEL</ns2:var2>
        <ns2:var3>04/04/2011</ns2:var3>
        <ns2:var4>Organization</ns2:var4>
        <ns2:UserId>46</ns2:UserId>
        <ns2:UserId>237</ns2:UserId>
        <ns2:UserId>46</ns2:UserId>
    </ns2:Details>
    

    生产环境 :

    <root xmlns:ns2="ns2">
        <ns2:Details>
            <ns2:var1>AA0511201143</ns2:var1>
            <ns2:var2>PARCEL</ns2:var2>
            <ns2:var3>04/04/2011</ns2:var3>
            <ns2:var4>Organization</ns2:var4>
            <ns2:UserId>46</ns2:UserId>
        </ns2:Details>
        <ns2:Details>
            <ns2:var1>AA0511201143</ns2:var1>
            <ns2:var2>PARCEL</ns2:var2>
            <ns2:var3>04/04/2011</ns2:var3>
            <ns2:var4>Organization</ns2:var4>
            <ns2:UserId>237</ns2:UserId>
        </ns2:Details>
    </root>
    
  • 0

    实现所需结果的一种方法是使用 Identity Transformation 并覆盖 ns2:Details 节点 .

    在重写模板中,您可以使用重复指令 xsl:for-each 迭代所有 UserId .

    要管理重复 UserId ,您可以使用来自Menuchian分组方法的众所周知的谓词 .

    因为我们将使用身份转换,所以生成所有事物的方式要简单得多 .

    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:ns2="ns">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:key name="UserId" match="ns2:UserId" use="."/>
    
        <xsl:template match="node()|@*">
            <xsl:copy>
                <xsl:apply-templates select="node()|@*"/>
            </xsl:copy>
        </xsl:template>
    
        <xsl:template match="ns2:Details">
            <xsl:for-each select="ns2:UserId
                          [generate-id()
                           = generate-id(key('UserId',.)[1])]">
                <ns2:Details>
                    <xsl:copy-of select="../@*"/>
                    <xsl:apply-templates select="../node()
                        [not(self::ns2:UserId)]"/>
                    <xsl:apply-templates select="."/>
                </ns2:Details>
            </xsl:for-each>
        </xsl:template>
    
    </xsl:stylesheet>
    

    当此变换应用于问题中提供的输入时,将获得以下片段:

    <ns2:Details xmlns:ns2="ns">
       <ns2:var1>AA0511201143</ns2:var1>
       <ns2:var2>PARCEL</ns2:var2>
       <ns2:var3>04/04/2011</ns2:var3>
       <ns2:var4>Organization</ns2:var4>
       <ns2:UserId>46</ns2:UserId>
    </ns2:Details>
    <ns2:Details xmlns:ns2="ns">
       <ns2:var1>AA0511201143</ns2:var1>
       <ns2:var2>PARCEL</ns2:var2>
       <ns2:var3>04/04/2011</ns2:var3>
       <ns2:var4>Organization</ns2:var4>
       <ns2:UserId>237</ns2:UserId>
    </ns2:Details>
    

    即使输入文档中存在重复的UserId,也会获得此输出 .

  • 3

    除了XSLT 2.0中的内容之外,它很简单而不是使用apply-templates编写多个temlates,使用单个模板查看下面的代码,它将给出相同的结果 .

    <xsl:for-each-group select="*:Details" group-by="*:UserId">
    
    
            <xsl:comment select="current-grouping-key()"/>
    
    
            <ns2:Details>
    
    
                <xsl:for-each select="current-group()">
    
    
                    <xsl:element name="ns2:UserId">
    
    
                        <xsl:value-of select="current-grouping-key()"/>
                    </xsl:element>
    
    
                    <xsl:copy-of select="*[name() != 'ns2:UserId']"/>
    
    
                </xsl:for-each>
    
    
            </ns2:Details>
    
    
        </xsl:for-each-group>
    
    
    </xsl:template>
    
  • 0

    在XSLT 1.0上有两个更紧凑的版本,结果相同 .

    • 基于generate-id()
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:ns2="ns">
    
        <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:key name="k1" match="/ns2:Details/ns2:UserId" use="."/>
        <xsl:key name="k2" match="/ns2:Details/ns2:UserId" use="generate-id() = generate-id(key('k1',.)[1])"/>
    
        <xsl:template match = "/">
            <xsl:for-each select="key('k2',true())">
                <ns:Details>
                    <xsl:copy-of select="../node()[not(self::ns2:UserId)]"></xsl:copy-of>
                    <xsl:copy-of select="."/>
                </ns:Details>
            </xsl:for-each>
        </xsl:template>
    
    </xsl:stylesheet>
    
    • 基于前兄弟
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"  xmlns:ns2="ns">
    
        <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:key name="k" match="/ns2:Details/ns2:UserId" use="not(node() = preceding-sibling::ns2:UserId/node())"/>
    
        <xsl:template match = "/">
            <xsl:for-each select="key('k',true())">
                <ns:Details>
                    <xsl:copy-of select="../node()[not(self::ns2:UserId)]"></xsl:copy-of>
                    <xsl:copy-of select="."/>
                </ns:Details>
            </xsl:for-each>
        </xsl:template>
    
    </xsl:stylesheet>
    

相关问题