2013-08-28 41 views
3

我正在嘗試使用xslt處理一些舊數據文件,並且它們在對象描述語言(ODL)中包含具有XML結構的大文本元素。我正在嘗試使用analyze-string將這些結構轉換爲xml。我可以匹配字符串,並採取適當的行動,但我無法弄清楚如何結構翻譯...使用xslt2將結構化文本轉換爲XML

輸入:

<?xml version="1.0" encoding="UTF-8"?> 
<h4:HDF4map version="1.0.1" 
    xsi:schemaLocation="http://www.hdfgroup.org/HDF4/XML/schema/HDF4map/1.0.1/HDF4map.xsd" 
    xmlns:h4="http://www.hdfgroup.org/HDF4/XML/schema/HDF4map/1.0.1" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <h4:HDF4FileContents> 
     <h4:FileAttribute name="StructMetadata" origin="File Attribute: Arrays" combinesMultipleAttributes="true" id="ID_FA2"> 
      <h4:stringValue> 
    GROUP=SwathStructure 
     GROUP=SWATH_1 
      SwathName="L2_Support_atmospheric&amp;surface_product" 
      GROUP=Dimension 
       OBJECT=Dimension_1 
        DimensionName="GeoXTrack" 
        Size=30 
       END_OBJECT=Dimension_1 
       OBJECT=Dimension_2 
        DimensionName="GeoTrack" 
        Size=45 
       END_OBJECT=Dimension_2 
      END_GROUP=Dimension 
      GROUP=GeoField 
       OBJECT=GeoField_1 
        GeoFieldName="Latitude" 
        DataType=DFNT_FLOAT64 
        DimList=("GeoTrack","GeoXTrack") 
       END_OBJECT=GeoField_1 
       OBJECT=GeoField_2 
        GeoFieldName="Longitude" 
        DataType=DFNT_FLOAT64 
        DimList=("GeoTrack","GeoXTrack") 
       END_OBJECT=GeoField_2 
       OBJECT=GeoField_3 
        GeoFieldName="Time" 
        DataType=DFNT_FLOAT64 
        DimList=("GeoTrack","GeoXTrack") 
       END_OBJECT=GeoField_3 
      END_GROUP=GeoField 
     END_GROUP=SWATH_1 
    END_GROUP=SwathStructure 
     </h4:stringValue> 
     </h4:FileAttribute> 
    </h4:HDF4FileContents> 
</h4:HDF4map> 

我想給FileAttribute/stringValue的轉換爲:

<root xmlns:h4="http://www.hdfgroup.org/HDF4/XML/schema/HDF4map/1.0.1"> 
    <group name="SwathStructure"> 
     <group name="SWATH_1"> 
     <SwathName>"L2_Support_atmospheric&amp;surface_product"</SwathName> 
     <group name="Dimension"> 
      <Dimension_1> 
       <DimensionName>"GeoXTrack"</DimensionName> 
       <Size>30</Size> 
      </Dimension_1> 
      <Dimension_2> 
       <DimensionName>"GeoTrack"</DimensionName> 
       <Size>45</Size> 
      </Dimension_2> 
     </group> 
     <group name="GeoField"> 
      <GeoField_1> 
       <GeoFieldName>"Latitude"</GeoFieldName> 
       <DataType>DFNT_FLOAT64</DataType> 
       <DimList>("GeoTrack","GeoXTrack")</DimList> 
      </GeoField_1> 
      <GeoField_2> 
       <GeoFieldName>"Longitude"</GeoFieldName> 
       <DataType>DFNT_FLOAT64</DataType> 
       <DimList>("GeoTrack","GeoXTrack")</DimList> 
      </GeoField_2> 
      <GeoField_3> 
       <GeoFieldName>"Time"</GeoFieldName> 
       <DataType>DFNT_FLOAT64</DataType> 
       <DimList>("GeoTrack","GeoXTrack")</DimList> 
      </GeoField_3> 
     </group> 
     </group> 
    </group> 
</root> 

這是我到目前爲止有:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xmlns:h4="http://www.hdfgroup.org/HDF4/XML/schema/HDF4map/1.0.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:xlink="http://www.w3.org/1999/xlink" exclude-result-prefixes="xsi xlink"> 

    <!-- Parameters to identify files to process --> 
    <xsl:param name="recordSetPath"/> 
    <xsl:param name="fileNamePattern"/> 
    <xsl:output method="xml" indent="yes"/> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="/"> 
    <xsl:element name="root"> 
     <xsl:namespace name="h4" select="'http://www.hdfgroup.org/HDF4/XML/schema/HDF4map/1.0.1'"/> 
     <xsl:variable name="xmlFilesSelect" select="concat($recordSetPath, '?select=',$fileNamePattern)"/> 
     <xsl:for-each select="collection(iri-to-uri($xmlFilesSelect))"> 
     <xsl:apply-templates/> 
     </xsl:for-each> 
    </xsl:element> 
    </xsl:template> 
    <xsl:template match="h4:FileAttribute[@name='StructMetadata']"> 
    <xsl:variable name="elementValue" select="h4:stringValue"/> 
    <xsl:analyze-string select="$elementValue" regex="(.*)=(.*)"> 
     <xsl:matching-substring> 
     <xsl:variable name="objectName" select="normalize-space(regex-group(1))"/> 
     <xsl:variable name="objectValue" select="normalize-space(regex-group(2))"/> 
     <xsl:choose> 
      <xsl:when test="$objectName='GROUP'"> 
      <xsl:element name="group"> 
       <xsl:attribute name="name" select="$objectValue"/> 
      </xsl:element> 
      </xsl:when> 
      <xsl:when test="contains($objectName,'END-GROUP')"> 
      <xsl:value-of select="'&lt;/group>'"/> 
      </xsl:when> 
      <xsl:when test="$objectName='OBJECT'"> 
      <xsl:element name="{$objectValue}"/> 
      </xsl:when> 
      <xsl:when test="contains($objectName,'END-OBJECT')"> 
      <xsl:value-of select="'&lt;/group>'"/> 
      </xsl:when> 
      <xsl:otherwise> 
      <xsl:element name="{$objectName}"> 
       <xsl:value-of select="$objectValue"/> 
      </xsl:element> 
      </xsl:otherwise> 
     </xsl:choose> 
     </xsl:matching-substring> 
    </xsl:analyze-string> 
    </xsl:template> 
    <xsl:template match="text()"/> 
</xsl:stylesheet> 

回答

1

這是不是一個完整的SOLUT離子(還)。但是我會首先通過輸入創建簡單的XML來解決這個問題。然後處理這個新的XML樹。儘管您可能需要使用pull處理方法而不是push(即,它實際上可能不適用於apply-templates ...),但應該可以使用apply-templates。

這些模板爲您的數據創建了一個簡單的XML,使每行的等號之前的內容成爲元素的文本節點之後的元素名稱和內容。

<xsl:template match="h4:stringValue"> 
    <xsl:variable name="newRoot"> 
    <xsl:for-each select="tokenize(.,'&#xA;')"> 
       <xsl:variable name="newElementName" select="substring-before(.,'=')"/> 
      <xsl:if test="$test ne '' and $test ne ' '" > 
       <xsl:element name="{$newElementName}"> 
        <xsl:value-of select="substring-after(.,'=')"/> 
       </xsl:element> 
      </xsl:if> 
    </xsl:for-each>  
    </xsl:variable> 
    <xsl:sequence select="$newRoot"/> 
    <xsl:apply-templates select="$newRoot" mode="process"/> 

</xsl:template> 
<xsl:template match="text()"/> 
+1

感謝您的正確方向的好點 –

1

的數據將需要超級一致的這個工作,但我會做的是創建一箇中間XML結構(如提出user5923),然後處理這一點。

該解決方案使用了很多disable-output-escaping,並且很容易導致輸出不完整。對於這個例子它工作正常,但如果你基於永久解決方案,請謹慎使用。

XML輸入

<h4:HDF4map version="1.0.1" 
    xsi:schemaLocation="http://www.hdfgroup.org/HDF4/XML/schema/HDF4map/1.0.1/HDF4map.xsd" 
    xmlns:h4="http://www.hdfgroup.org/HDF4/XML/schema/HDF4map/1.0.1" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <h4:HDF4FileContents> 
     <h4:FileAttribute name="StructMetadata" origin="File Attribute: Arrays" combinesMultipleAttributes="true" id="ID_FA2"> 
      <h4:stringValue> 
       GROUP=SwathStructure 
       GROUP=SWATH_1 
       SwathName="L2_Support_atmospheric&amp;surface_product" 
       GROUP=Dimension 
       OBJECT=Dimension_1 
       DimensionName="GeoXTrack" 
       Size=30 
       END_OBJECT=Dimension_1 
       OBJECT=Dimension_2 
       DimensionName="GeoTrack" 
       Size=45 
       END_OBJECT=Dimension_2 
       END_GROUP=Dimension 
       GROUP=GeoField 
       OBJECT=GeoField_1 
       GeoFieldName="Latitude" 
       DataType=DFNT_FLOAT64 
       DimList=("GeoTrack","GeoXTrack") 
       END_OBJECT=GeoField_1 
       OBJECT=GeoField_2 
       GeoFieldName="Longitude" 
       DataType=DFNT_FLOAT64 
       DimList=("GeoTrack","GeoXTrack") 
       END_OBJECT=GeoField_2 
       OBJECT=GeoField_3 
       GeoFieldName="Time" 
       DataType=DFNT_FLOAT64 
       DimList=("GeoTrack","GeoXTrack") 
       END_OBJECT=GeoField_3 
       END_GROUP=GeoField 
       END_GROUP=SWATH_1 
       END_GROUP=SwathStructure 
      </h4:stringValue> 
     </h4:FileAttribute> 
    </h4:HDF4FileContents> 
</h4:HDF4map> 

XSLT 2.0

<xsl:stylesheet version="2.0" xmlns:h4="http://www.hdfgroup.org/HDF4/XML/schema/HDF4map/1.0.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="/h4:HDF4map/h4:HDF4FileContents/h4:FileAttribute[@name='StructMetadata']/h4:stringValue"> 
     <xsl:variable name="pass1"> 
      <xsl:analyze-string select="." regex="([^=\s]+)=([^=\s]+)"> 
       <xsl:matching-substring> 
        <tag name="{regex-group(1)}" value="{regex-group(2)}"/> 
       </xsl:matching-substring> 
       <xsl:non-matching-substring/> 
      </xsl:analyze-string>   
     </xsl:variable> 
     <root> 
      <xsl:for-each select="$pass1/tag"> 
       <xsl:choose> 
        <xsl:when test="@name='END_OBJECT'"> 
         <xsl:value-of select="concat('&lt;/',@value,'>&#xA;')" disable-output-escaping="yes"/> 
        </xsl:when> 
        <xsl:when test="starts-with(@name,'END_')"> 
         <xsl:value-of select="concat('&lt;/',lower-case(substring-after(@name,'END_')),'>&#xA;')" disable-output-escaping="yes"/> 
        </xsl:when> 
        <xsl:otherwise> 
         <xsl:choose> 
          <xsl:when test="@name='OBJECT'"> 
           <xsl:value-of select="concat('&lt;',@value,'>&#xA;')" disable-output-escaping="yes"/> 
          </xsl:when>      
          <xsl:when test="following-sibling::*[@name=concat('END_',current()/@name)]"> 
           <xsl:value-of select="concat('&lt;',lower-case(@name),' name=&quot;')" disable-output-escaping="yes"/> 
           <xsl:value-of select="replace(@value,'^&quot;|&quot;$','')"/> 
           <xsl:value-of select="'&quot;>&#xA;'" disable-output-escaping="yes"/>        
          </xsl:when> 
          <xsl:otherwise> 
           <xsl:value-of select="concat('&lt;',@name,'>')" disable-output-escaping="yes"/> 
           <xsl:value-of select="@value"/> 
           <xsl:value-of select="concat('&lt;/',@name,'>&#xA;')" disable-output-escaping="yes"/> 
          </xsl:otherwise> 
         </xsl:choose>      
        </xsl:otherwise> 
       </xsl:choose> 
      </xsl:for-each>   
     </root> 
    </xsl:template> 

</xsl:stylesheet> 

XML輸出(我格式化輸出,使其更易於閱讀。有一些&#xA;用於輸出中斷以幫助格式化,但這些可以刪除。)

<root xmlns:h4="http://www.hdfgroup.org/HDF4/XML/schema/HDF4map/1.0.1"> 
    <group name="SwathStructure"> 
     <group name="SWATH_1"> 
      <SwathName>"L2_Support_atmospheric&amp;surface_product"</SwathName> 
      <group name="Dimension"> 
       <Dimension_1> 
        <DimensionName>"GeoXTrack"</DimensionName> 
        <Size>30</Size> 
       </Dimension_1> 
       <Dimension_2> 
        <DimensionName>"GeoTrack"</DimensionName> 
        <Size>45</Size> 
       </Dimension_2> 
      </group> 
      <group name="GeoField"> 
       <GeoField_1> 
        <GeoFieldName>"Latitude"</GeoFieldName> 
        <DataType>DFNT_FLOAT64</DataType> 
        <DimList>("GeoTrack","GeoXTrack")</DimList> 
       </GeoField_1> 
       <GeoField_2> 
        <GeoFieldName>"Longitude"</GeoFieldName> 
        <DataType>DFNT_FLOAT64</DataType> 
        <DimList>("GeoTrack","GeoXTrack")</DimList> 
       </GeoField_2> 
       <GeoField_3> 
        <GeoFieldName>"Time"</GeoFieldName> 
        <DataType>DFNT_FLOAT64</DataType> 
        <DimList>("GeoTrack","GeoXTrack")</DimList> 
       </GeoField_3> 
      </group> 
     </group> 
    </group> 
</root> 
+0

這個答案效果很好,是一個很好的起點。非常感謝... –