选择性复制和更新使用XSLT XML节点(Selectively copy and update x

2019-08-17 04:01发布

我正与一个xml,我需要复制和更新,以传递进行进一步的处理工作。 我遇到的问题是,我还没有想出一个有效的方法来做到这一点。 从本质上讲,我想更新一些数据,有条件,然后复制未更新的所有节点。 为什么这是具有挑战性的是由于体积和方差中节点的数量和名称被复制。 我也想不复制没有文本价值的节点。 下面是一个例子:

输入XML

  <root>
     <PersonProfile xmlns:'namespace'>
        <ID>0001</ID>
        <Name>
           <FirstName>Jonathan</FirstName>
           <PreferredName>John</PreferredName>
           <MiddleName>A</MiddleName>
           <LastName>Doe</LastName>
        </Name>
        <Country>US</Country>
        <Biirthdate>01-01-1980</Birthdate>
        <BirthPlace>
           <City>Townsville</City>
           <State>OR</State>
           <Country>US</Country>
        </Birthplace>
        <Gender>Male</Gender>
        <HomeState>OR</HomeState>
        ...
        <nodeN>text</nodeN>
     </PersonProfile>
 </root>

所述“PersonProfile”节点仅仅是“根”元素内的几个节点集合中的一个,每个都有自己的数据的子集。 如邮寄地址,紧急联系人信息等什么,我试图做的是更新的节点,如果变量有一个新的价值为他们再复制未更新的所有节点。

这是我目前的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">

 <xsl:variable name='updateData' select='document("report")'/>

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

 <!-- Template to update Person Profile -->
  <xsl:template match='PersonProfile'>   
    <xsl:copy>
        <xsl:apply-templates select='*'/>    
        <xsl:element name='Name'>
            <xsl:if test='exists($updateData/Preferred)'>
               <xsl:element name='FirstName'>
                  <xsl:value-of select='$reportData/FirstName'/>
               </xsl:element>
            </xsl:if>            
            <xsl:if test='exists($updateData/Preferred)'>
               <xsl:element name='PreferredName'>
                   <xsl:value-of select='$updateData/Preferred'/>
               </xsl:element>
            </xsl:if>
            <xsl:if test='exists($updateData/Middle)'>
            <xsl:element name='MiddleName'>
                <xsl:value-of select='$updateData/Middle'/>
            </xsl:element>
            </xsl:if>
            <xsl:if test='exists($updateData/LastName)'>
               <xsl:element name='LastName'>
                   <xsl:value-of select='$updateData/wd:LastName'/>
               </xsl:element>
            </xsl:if> 
         </xsl:element>
         <xsl:if test='exists($updateData/Country)'>
            <xsl:element name='Country'>
               <xsl:value-of select='$updateData/Country'/>
            </xsl:element>
         </xsl:if> 
         ....
         <!-- follows same structure until end of template -->
    </xsl:copy>
  </xsl:template>

 <!-- More Templates to Update other Node sets -->

</xsl:stylesheet>

这是怎么回事,现在,是它的复制所有的节点,然后添加更新的值。 使用撒克逊PE 9.3.0.5,我会得到类似这样的输出:

样本输出

  <root>
     <PersonProfile xmlns:'namespace'>
        <ID>0001</ID>
        <Name>
           <FirstName>Jonathan</FirstName>
           <PreferredName>John</PreferredName>
           <MiddleName>A</MiddleName>
           <LastName>Doe</LastName>
        </Name>
        <Country>US</Country>
        <Biirthdate>01-01-1980</Birthdate>
        <BirthPlace>
           <City>Townsville</City>
           <State>OR</State>
           <Country>US</Country>
        </Birthplace>
        <Gender>Male</Gender>
        <HomeState>OR</HomeState>
        ...
        <nodeN>text</nodeN>
        <PreferredName>Jonathan</PreferredName>
        <HomeState>WA</HomeState>
     </PersonProfile>
 </root>

我知道这种情况正在发生,因为我申请的模板中PersonProfile和我可以指定哪些节点要排除所有的节点,但我觉得这是一个非常贫穷的解决方案为节点的数量可能是30个或更多向上这将需要为每一个写入值。 我相信XML有着更优雅的解决方案,而不是明确列出的每个节点。 我想有一个出这样的:

所需的输出

  <root>
     <PersonProfile xmlns:'namespace'>
        <ID>0001</ID>
        <Name>
           <FirstName>Jonathan</FirstName>
           <PreferredName>Jonathan</PreferredName>
           <MiddleName>A</MiddleName>
           <LastName>Doe</LastName>
        </Name>
        <Country>US</Country>
        <Biirthdate>01-01-1980</Birthdate>
        <BirthPlace>
           <City>Townsville</City>
           <State>OR</State>
           <Country>US</Country>
        </Birthplace>
        <Gender>Male</Gender>
        <HomeState>WA</HomeState>
        ...
        <nodeN>text</nodeN>
     </PersonProfile>
 </root>

如果有人可以帮助我建立一个模板结构,将在XML结构的工作,我将不胜感激。 这将需要“重复使用”,因为有像人物简介类似节点的结构,我将不得不把它应用到,但与不同的节点名称和元素的数量,等等。

在此先感谢您的帮助!

  • Ĵ

Answer 1:

这应该为你原来的问题的工作:

<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">

  <xsl:variable name='updateData' select='document("report")'/>

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

  <xsl:template match='*[not(*)]'>
    <xsl:variable name='matchingValue' 
                  select='$updateData/*[name() = name(current())]'/>
    <xsl:choose>
      <xsl:when test='$matchingValue'>
        <xsl:copy>
          <xsl:apply-templates select='@*' />
          <xsl:value-of select='$matchingValue'/>
        </xsl:copy>
      </xsl:when>
      <xsl:when test='normalize-space()'>
        <xsl:call-template name='copy' />
      </xsl:when>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

至于将不存在源XML新的元素,这是棘手。 你可以打开该一个单独的问题? 我可以对如何处理一些想法。



文章来源: Selectively copy and update xml nodes using XSLT