2013-12-11 37 views
0

我有下面的XML文檔XSLT節點計數器

<root> 
    <TotalPeople>BLABLA</TotalPeople> 
     <MoreTagsWithData/> 
     <Person> 
      <id>bla-bla</id> 
      <Name>John Smith</Name> 
      <MoreTagsWithData/> 
     </Person> 
     <Person> 
      <id>bla-bla</id> 
      <Name>John Doe</Name> 
      <MoreTagsWithData/> 
     </Person> 
    </root> 

我需要得到

<root> 
<TotalPeople>2</TotalPeople> <!-- Needs to calculate how many "Person" tags --> 
    <MoreTagsWithData/> 
    <Person> 
     <id>1</id> <!-- incrementing per each Person --> 
     <Name>John Smith</Name> 
     <MoreTagsWithData/> 
    </Person> 
    <Person> 
     <id>2</id> 
     <Name>John Doe</Name> 
     <MoreTagsWithData/> 
    </Person> 
</root> 

我試圖XSLT模板文件:

<!-- copy all file (I need to save the whole file since in reality it contains much more data --> 

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

<!-- indexing ids --> 
    <xsl:template match="id"> 
    <xsl:copy> 
       <xsl:number level="any"/> 
    </xsl:copy> 
</xsl:template> 


<!-- Piece I am not sure , it does not work --> 

    <xsl:template match="TotalPeople"> 
     <xsl:copy> 
       <xsl:number level="any" count="/root/Person/id"/> 
     </xsl:copy> 
    </xsl:template> 

我需要計算文檔中有多少個標籤,並使用此值修改文檔中的特殊標籤。我無法創建新文檔,因爲真正的文檔包含很多信息,我需要維護它。

<xsl:template match="TotalPeople"> 
    <xsl:copy> 
     <xsl:value-of select="count(/root/Person/id)"/> 
     <!-- or just select="count(/root/Person)" --> 
    </xsl:copy> 
</xsl:template> 

XSLT樣式表被設計成一個輸入XML文檔轉換到一個單獨的輸出文檔,而不是編輯就地文件:

回答

0

如下您可以更改最後一個模板。以上將生成您請求的輸出文檔,但不會修改您的現有文檔。至少,我不知道將會這樣做的XSLT處理器。相反,您可以刪除輸入XML文件並重命名輸出XML以替換它。

1

您可以使用類似下面樣式表的東西,並將您的輸入XML文檔轉換爲單獨的輸出文檔,如@LarsH所述。

XSLT 1.0

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

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

    <xsl:template match="TotalPeople"> 
     <xsl:copy> 
      <xsl:value-of select="count(../Person)"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="id"> 
     <xsl:copy> 
      <xsl:number count="Person"/> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

但是,如果你能使用XSLT 2.0,你可以嘗試使用collection()xsl:result-documentdocument-uri()覆蓋原來的文件。這有點怪異,我仍然建議刪除輸入XML並重命名輸出XML。

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:param name="dir" select="'C:/Path/To/Doc'"/> 
    <xsl:param name="file" select="'input.xml'"/> 

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

    <xsl:template match="/"> 
     <xsl:for-each select="collection(concat('file:///',$dir,'?select=',$file))"> 
      <xsl:result-document href="{document-uri(current())}"> 
       <xsl:apply-templates/> 
      </xsl:result-document> 
     </xsl:for-each> 
    </xsl:template> 

    <xsl:template match="TotalPeople"> 
     <xsl:copy> 
      <xsl:value-of select="count(../Person)"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="id"> 
     <xsl:copy> 
      <xsl:number count="Person"/> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 
+0

有趣(我只用撒克遜-HE 9.4。測試這一點)......我還沒有意識到,你能做到這一點。如果覆蓋輸入文檔,是否保證在讀完原稿之前不會開始覆蓋? – LarsH

+1

@LarsH - 我不確定。由於不是流式傳輸,我認爲整個輸入必須在處理/覆蓋開始之前被讀取和存儲在內存中。我只做了兩次,兩次都是堆棧溢出的答案。測試時我沒有遇到任何問題,但數據集很小。 –