2013-02-26 35 views
-1

我正在處理一個需要複製和更新以傳遞進行進一步處理的xml。我遇到的問題是我沒有想出一個有效的方法來做到這一點。實質上,我想有條件地更新一些數據,然後複製所有未更新的節點。爲什麼這是具有挑戰性的,是由於要複製的節點的數量和名稱的數量和方差。我也不想複製沒有文本值的節點。下面是一個例子:使用XSLT有選擇地複製和更新xml節點

INPUT 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結構的工作,我將不勝感激。它需要是「可重用的」,因爲有類似的節點結構,比如我需要應用它的Person Profile,但節點名稱和元素數量不同,等等。

  • Ĵ
+0

所以我找到了一個潛在的解決方案,基本上我爲每個xpath創建了一個模板,可以更新然後應用它們 - 哪個工作得很好。我只有1個問題 - 當路徑不存在時如何使用模板!可以說這個人缺少主頁狀態 - 我無法匹配做,所以我怎麼能告訴模板來建立新的節點? 謝謝! – 2013-02-26 03:10:04

回答

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,這是棘手的新元素。你能爲此打開一個單獨的問題嗎?我可能對如何解決這個問題有一些想法。

+0

謝謝!我會馬上測試一下。至於我的第二個問題,我創建了這個帖子。 http://stackoverflow.com/questions/15081758/insert-xpath-during-copy-using-apply-templates 再次感謝您提供的任何幫助! – 2013-02-26 05:08:58

+0

雖然這對我不起作用,但我仍然接受了答案,因爲它在1假設下是正確的 - updateData變量中的xpath將與源xml中的元素名稱匹配。我沒有具體說明情況並非總是如此。我想我仍然可以修改這個工作,但只是爲了澄清源xpath /元素名稱與updateData變量中的數據的xpath不匹配。再次感謝您的答案! – 2013-02-26 14:02:13