在排除父节点,删除特定子节点以及覆盖某些子节点时复制XML

时间:2013-02-18 05:04:29

标签: xslt insert copy parent-child

我已经回顾了几个分别完成这些事情的帖子,但还没有成功地将它们组合在一起。

我有类似于这种结构的输入:

 <Response>
    <Confirmation>Success</Confirmation>
    <SecondResponse>
       <InquiryResponse>
          <ID>99999</ID>
          <Confirmation>Success</Confirmation>
          <Exception/>
          <!-- The following structure repeats a varying amount of times -->
          <DataNode1>
             <!-- Child nodes could be null, transform should remove null nodes -->
             <Child1>data</Child1>
             ...
             <Childn>dataN</Childn>
          </DataNode1>
          ...
          <DataNodeN>
             <Child1>data</Child1>
             ...
             <Childn>dataN</Childn>
          </DataNodeN>
       </InquiryResponse>
    </SecondResponse>
 </Response>

现在,我需要完成以下事项:

1)复制<InquiryResponse>(但不是<InquiryResponse>本身)的所有子节点

2)排除<Confirmation><Exception>节点

3)排除DataNode中的所有空子项

4)在DataNode中插入一个新的子元素

所以期望的输出看起来像这样:

 <ID>99999</ID>
 <DataNode1>
   <Child1>data</Child1>
   <ChiildInsert>newData</ChildInsert>
   <Childn>dataN</Childn>
 </DataNode1>
 ...
 <DataNodeN>
    <Child1>data</Child1>
    <ChildInsert>newData</ChildInsert>
    <Childn>dataN</Childn>
 </DataNodeN>

我相信我必须通过为每个DataNode创建一个模板(我知道可能发生的所有可能值),以及删除我不想要的节点的模板,然后将它们全部应用到主副本模板忽略空节点。这是我目前使用2.0的XSLT版本 - 虽然我知道它并不完全完整,但就我而言:

 <xsl:stylesheet version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"   
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

  <!-- Remove Unwanted Nodes -->
  <xsl:template match='Confirmation|Exception'/>

  <!-- DataNode Template -->
  <template match='DataNode1'>
    <xsl:copy>
       <xsl:apply-templates select="@*|node()"/>
       <ChildInsert>
          <xsl:value-of select='newData'/>
       </ChildInsert>
    </xsl:copy>
  </xsl:template>

  <!-- Identity Transform -->
  <xsl:template match='@*|node()'> 
    <xsl:if test='. != ""'>
       <xsl:copy>
         <xsl:apply-templates select='@*|node()'/>
       </xsl:copy>
    </xsl:if>
  </xsl:template>

  </xsl:stylesheet>

这是我使用Saxon-PE 9.3.0.5生成的输出

 <Response>
   <SecondResponse>
     <InquiryResponse>
         <ID>99999</ID>
         <DataNode1>
            <Child1>data</Child1>
            <ChiildInsert>newData</ChildInsert>
            <Childn>dataN</Childn>
         </DataNode1>
         ....
         <DataNodeN>...</DataNodeN>
     </InquiryResponse>
   </SecondResponse>
 </Response>

显然,我还没有得到所有的回复家长,因为我没有指定处理它们的方法;但是,每当我尝试将模板与XPath匹配时,我都会得到数据,而不是XML。我知道我可以通过另一个只复制<InquiryResponse>的子节点的转换来传递它,但我觉得应该有更优雅的方式来代替它。以下是我仍然面临的问题/问题。

1)由于使用这样的模板:<xsl:template match='Response'/>会使我的整个响应无效,我尝试将标识模板切换为匹配Response/SecondResponse/InquiryResponse/*,但结果只生成文本数据,而不是XML。

2)当<Exception>节点填充了一个值时,它会继续被复制而不是像<Confirmation>节点一样被删除。

3)如果我想更新非null的子节点的值,我会这样做吗?还有一个额外的要求是更新一些子节点,所以我仍在考虑如何做,这似乎是正确的方法,但我想验证。

 <xsl:template match='childNodeA'>
     <childNodeA>
        <xsl:value-of select='someValue/>
     </childNodeA>
 </xsl:template> 

如果不清楚我会道歉,但随时可以请求您提供的任何进一步细节,并提前感谢任何可以提供帮助的人。

1 个答案:

答案 0 :(得分:8)

您发布的输出XML格式不正确,因为它没有根元素,但是这个XSLT 1.0样式表应该按照您的意愿执行:

<强>样式表

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" encoding="utf-8"/>
  <xsl:strip-space elements="*"/>

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

  <!-- Apply all child nodes; don't copy the element itself -->
  <xsl:template match="Response | SecondResponse | InquiryResponse">
    <xsl:apply-templates/>
  </xsl:template>

  <!-- Drop elements -->
  <xsl:template match="Confirmation | Exception"/>

  <xsl:template match="DataNode1 | DataNode2 | DataNodeN">
    <xsl:copy>
      <!-- Apply Child1, ignore children with no text content -->
      <xsl:apply-templates select="Child1[normalize-space(.)]"/>
      <!-- Insert new element -->
      <ChildInsert>newData</ChildInsert>
      <!-- Apply all other child elements except Child1 -->
      <xsl:apply-templates select="*[normalize-space(.)][not(self::Child1)]"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

<强>输入

<Response>
  <Confirmation>Success</Confirmation>
  <SecondResponse>
     <InquiryResponse>
        <ID>99999</ID>
        <Confirmation>Success</Confirmation>
        <Exception/>
        <!-- The following structure repeats a varying amount of times -->
        <DataNode1>
           <!-- Child nodes could be null, transform should remove null nodes -->
           <Child1>data</Child1>
           <Childn>dataN</Childn>
        </DataNode1>
        <DataNodeN>
           <Child1>data</Child1>
           <Childn>dataN</Childn>
        </DataNodeN>
     </InquiryResponse>
  </SecondResponse>
</Response>

<强>输出

<?xml version="1.0" encoding="utf-8"?>
<ID>99999</ID>
<DataNode1>
  <Child1>data</Child1>
  <ChildInsert>newData</ChildInsert>
  <Childn>dataN</Childn>
</DataNode1>
<DataNodeN>
  <Child1>data</Child1>
  <ChildInsert>newData</ChildInsert>
  <Childn>dataN</Childn>
</DataNodeN>

请注意,由于您没有指定“null”的含义,我认为它是指没有文本内容的元素。所以上面的代码会丢弃一个<Child1>元素,如下所示:

<Child1>
  <GrandChild1/>
</Child1>