【问题标题】:Is xslt good approach to convert text to xml structure?xslt 是将文本转换为 xml 结构的好方法吗?
【发布时间】:2011-11-21 21:53:04
【问题描述】:

我正在尝试找到一个更好的解决方案来将纯文本(但每个字段都有预定义的长度)转换为 xml。 例如输入文本可以是 “Testuser new york 10018”,前11个字符表示用户名,后12个字符表示城市,后5个字符表示邮政编码。 所以我需要从上面的字符串中形成一个带有预定义字段长度的 xml。

我在考虑两种方法

  1. 定义一个业务实体并通过对输入文本使用子字符串函数填充实体属性,然后将实体序列化为xml

  2. 预定义 xml 结构,使用 xslt 导航到每个节点并填充值 在输入文本上使用子字符串函数。

【问题讨论】:

    标签: c# .net xslt fixed-length-record


    【解决方案1】:

    以下语句:(XSLT) "isn't suitable for transforming from structured text to XML. " 和语句 "XSLTmusthave XML as the input document" **都是错误的

    我正在考虑两种方法

    1. 定义一个业务实体并通过在输入文本上使用子字符串函数填充实体属性,然后将实体序列化为 xml

    2. 预定义 xml 结构,使用 xslt 导航到每个节点,并在输入文本上使用子字符串函数填充值。

    事实上,方法 2 使用 XSLT 很容易实现

    我。 XSLT 1.0

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:template match="/*/text()" name="processLines">
      <xsl:param name="pText" select="."/>
    
      <xsl:if test="contains($pText, '&#xA;')">
        <xsl:variable name="vLine" select=
         "substring-before($pText, '&#xA;')"/>
    
         <user>
           <name>
             <xsl:value-of select=
             "translate(substring-before($vLine, ' '),'_',' ')"/>
           </name>
           <city>
             <xsl:value-of select=
             "translate(substring-before(substring-after($vLine, ' '),' '),
                        '_',
                        ' '
                        )
             "/>
           </city>
           <zipCode>
             <xsl:value-of select=
             "translate(substring-after(substring-after($vLine, ' '),' '),
                        '_',
                        ' '
                        )
             "/>
           </zipCode>
         </user>
    
         <xsl:call-template name="processLines">
          <xsl:with-param name="pText" select=
          "substring-after($pText, '&#xA;')"/>
         </xsl:call-template>
      </xsl:if>
      </xsl:template>
    </xsl:stylesheet>
    

    当此转换应用于特殊格式的文本时(包装在单个顶部元素中以形成良好的格式——正如我们将在 XSLT 2.0 中看到的那样,这种包装不是必需的) :

    <t>Testuser new_york 10018
    usera seattle 98000
    userb bellevue 98004
    userb redmond 98052
    </t>
    

    产生想要的结果

    <user>
       <name>Testuser</name>
       <city>new york</city>
       <zipCode>10018</zipCode>
    </user>
    <user>
       <name>usera</name>
       <city>seattle</city>
       <zipCode>98000</zipCode>
    </user>
    <user>
       <name>userb</name>
       <city>bellevue</city>
       <zipCode>98004</zipCode>
    </user>
    <user>
       <name>userb</name>
       <city>redmond</city>
       <zipCode>98052</zipCode>
    </user>
    

    注意事项

    1. 这只是一个演示如何完成任务的演示。这就是为什么我不处理固定宽度的字段(虽然会更容易),而是处理空格分隔的值。

    2. 任何值中包含的任何空格都在输入中作为下划线输入(或我们选择的任何字符,我们知道这些字符永远不会成为任何值的一部分。在输出时,任何下划线都将转换为实际空格。

    二。 XSLT 2.0 解决方案

    <xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:variable name="vText" select=
      "unparsed-text('file:///c:/temp/delete/delete.txt')"/>
    
     <xsl:variable name="vLines" select=
      "tokenize($vText, '&#xD;?&#xA;')[normalize-space()]"/>
    
     <xsl:template match="/">
      <xsl:for-each select="$vLines">
        <xsl:variable name="vFields" select=
        "tokenize(., ' ')[normalize-space()]"/>
       <user>
         <name>
           <xsl:sequence select="translate($vFields[1], '_',' ')"/>
         </name>
         <city>
           <xsl:sequence select="translate($vFields[2], '_',' ')"/>
         </city>
         <zipCode>
           <xsl:sequence select="translate($vFields[3], '_',' ')"/>
         </zipCode>
       </user>
      </xsl:for-each>
     </xsl:template>
    </xsl:stylesheet>
    

    当此转换应用于任何 XML 文档时(未使用且实际上不需要,因为在 XSLT 2.0 中不需要有源 XML 文档),并且 如果文件C:\temp\delete\delete.txt

    Testuser new_york 10018
    usera seattle 98000
    userb bellevue 98004
    userb redmond 98052
    

    再次产生所需的正确结果

    <user>
       <name>Testuser</name>
       <city>new york</city>
       <zipCode>10018</zipCode>
    </user>
    <user>
       <name>usera</name>
       <city>seattle</city>
       <zipCode>98000</zipCode>
    </user>
    <user>
       <name>userb</name>
       <city>bellevue</city>
       <zipCode>98004</zipCode>
    </user>
    <user>
       <name>userb</name>
       <city>redmond</city>
       <zipCode>98052</zipCode>
    </user>
    

    注意事项

    1. 使用标准 XSLT 2.0 函数 unparsed-text()

    2. 使用标准 XPath 2.0 函数 tokenize()

    最后说明

    大多数复杂的文本处理都是完全在 XSLT 中以工业方式完成的。 The FXSL library 包含一个通用 LR(1) parser 和一个 tweaked YACC that produces XML-formatted tables,它们是这个通用运行时 LR(1) 解析器的输入.

    使用这个工具,我成功地 built parsers 处理了 JSON 和 XPath 2.0 等复杂语言。

    【讨论】:

    • 非常感谢您的想法。我会尝试使用你建议的 xslt 库,看看它会变得很热
    【解决方案2】:

    XSLT 2.0 非常适合将结构化文本转换为 XML。您可能想在这里阅读 Stephanie Haupt 和 Maik Stuehrenberg 的 2010 年论文:

    http://www.balisage.net/Proceedings/vol5/html/Haupt01/BalisageVol5-Haupt01.html

    或者我自己 2008 年的论文

    http://www.saxonica.com/papers/ideadb-1.1/mhk-paper.xml

    用于案例研究。

    我通常不会尝试使用 XSLT 1.0 来完成这项任务,但正如 Dimitre 的回答所示,它可以在简单的情况下完成。

    【讨论】:

      猜你喜欢
      • 2012-02-06
      • 1970-01-01
      • 2011-01-17
      • 2013-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多