XML连接:如何使用标记标记连接节点,而不仅仅是使用XSLT的值

时间:2013-12-23 10:02:03

标签: xml xslt xpath concatenation batch-processing

我有以下XML用于Web服务的批处理,它只执行基本的算术运算。在处理期间,一些节点将失败,例如,由于非法参数,例如导致除零的那些(在示例中为第三节点)。我需要创建一个单独的XML文档来连接这些违规节点,或者由于某些其他原因而失败的节点。我无法想出一个合适的XPATH方法来连接XML片段。

源XML:

<Envelopes>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fc="http://fc.org/">
   <soapenv:Header/>
   <soapenv:Body>
      <fc:add>
         <arg0>99938</arg0>
         <arg1>62</arg1>
      </fc:add>
   </soapenv:Body>
</soapenv:Envelope>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fc="http://fc.org/">
   <soapenv:Header/>
   <soapenv:Body>
      <fc:addaaaaaaaaaa>
         <arg0>34</arg0>
         <arg1>223</arg1>
      </fc:addaaaaaaaaaa>
   </soapenv:Body>
</soapenv:Envelope>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fc="http://fc.org/">
   <soapenv:Header/>
   <soapenv:Body>
      <fc:divide>
         <arg0>634</arg0>
         <arg1>0</arg1>
      </fc:divide>
   </soapenv:Body>
</soapenv:Envelope>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:fc="http://fc.org/">
   <soapenv:Header/>
   <soapenv:Body>
      <fc:subtract>
         <arg0>3400</arg0>
         <arg1>2200</arg1>
      </fc:subtract>
   </soapenv:Body>
</soapenv:Envelope>
</Envelopes>

XSL转换

<xsl:stylesheet version=
"1.0" xmlns:xsl=
"http://www.w3.org/1999/XSL/Transform" xmlns:dp=xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:str="http://exslt.org/strings">
<xsl:output omit-xml-declaration="yes"/>


<xsl:template match="/">

<xsl:for-each select="/Envelopes/soapenv:Envelope">

<!-- introduce a variable for the current envelope -->
<xsl:variable name="fc" select="."/>

<!--  I NEED TO CONCAT THE ENTIRE NODE TO CREATE A BRAND NEW XML FILE -->

<xsl:variable name="addEnvelope" select="'&lt;Envelopes&gt;',."/>
   <xsl:message terminate="no" dp:priority="notice">
  <xsl:copy-of select="$addEnvelope"/>
</xsl:message>
<!-- I SEE THE OUTPUT <Envelopes>324 0  etc... WHAT I WANT IS TO GET AN OUTPUT LIKE: -->
<Envelopes><soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:fc="http://fc.org/">
   <soapenv:Header/>
   <soapenv:Body>
      <fc:multiply>
         <arg0>34</arg0>
         <arg1>2</arg1>
      </fc:multiply>
   </soapenv:Body>
</soapenv:Envelope>  etc...

</xsl:for-each>

1 个答案:

答案 0 :(得分:1)

由于问题有点模糊,很难给出确切的答案,但我建议你需要建立在XSLT identity transform之上。

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

在XSLT中,您不会“连接”节点,这是您对字符串执行的操作,但您可以将元素复制或创建新元素到输出树。上面的标识模板本身将文档中的所有节点复制到输出树。通过这样做,这意味着您真正需要做的就是添加模板来处理您想要更改的节点,或者在您的情况下,添加模板以停止复制节点。

例如,你提到了除零。假设您要创建仅包含 arg1 为零的包络元素的XML。这意味着,当与XSLT标识模板一起使用时,您只需要一个模板来忽略包络元素,其中 arg1 不为零。

<xsl:template match="soapenv:Envelope[not(soapenv:Body/fc:divide/arg1 = '0')]" />

就是这样!试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   
 xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:fc="http://fc.org/">
  <xsl:output method="yes" omit-xml-declaration="yes" indent="yes" />

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

  <xsl:template match="soapenv:Envelope[not(soapenv:Body/fc:divide/arg1 = '0')]" />
</xsl:stylesheet>

或者,如果您希望明确选择要复制的信封元素,而不是要复制,则可以创建一个模板以匹配信封元素,然后使用 xsl:apply-templates 选择您想要的。

此XSLT也应该起作用

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   
 xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
 xmlns:fc="http://fc.org/">
  <xsl:output method="yes" omit-xml-declaration="yes" indent="yes" />

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

  <xsl:template match="Envelopes">
    <xsl:apply-templates select="soapenv:Envelope[soapenv:Body/fc:divide/arg1 = '0']" />
  </xsl:template>
</xsl:stylesheet>