-1

私は、さらに処理するためにコピーして更新する必要がある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」ノードは、「ルート」要素内のいくつかのノード セットの 1 つにすぎず、それぞれに独自のデータ サブセットがあります。郵送先住所、緊急連絡先情報など。私がしようとしているのは、変数に新しい値がある場合にノードを更新し、更新されなかったすべてのノードをコピーすることです。

ここに私の現在の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>

現在起こっていることは、すべてのノードをコピーしてから更新値を追加していることです。Saxon-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 のような同様のノード構造があり、それを適用する必要があるため、「再利用可能」である必要がありますが、ノード名や要素数などが異なります。

助けてくれてありがとう!

  • J
4

1 に答える 1

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 に存在しない新しい要素を挿入する限り、それはよりトリッキーです。そのために別の質問を開いていただけますか?それにアプローチする方法について、いくつかのアイデアがあるかもしれません。

于 2013-02-26T04:32:59.110 に答える