XML в CSV с помощью справки XSLT - PullRequest
6 голосов
/ 17 мая 2010

Я бы хотел преобразовать XML в CSV с помощью XSLT, но при применении XSL из потока SO под названием XML To CSV XSLT против моего ввода:

<WhoisRecord>
  <DomainName>127.0.0.1</DomainName>
  <RegistryData>
    <AbuseContact>
      <Email>abuse@iana.org</Email>
      <Name>Internet Corporation for Assigned Names and Number</Name>
      <Phone>+1-310-301-5820</Phone>
    </AbuseContact>
    <AdministrativeContact i:nil="true"/>
    <BillingContact i:nil="true"/>
    <CreatedDate/>
    <RawText>...</RawText>
    <Registrant>
      <Address>4676 Admiralty Way, Suite 330</Address>
      <City>Marina del Rey</City>
      <Country>US</Country>
      <Name>Internet Assigned Numbers Authority</Name>
      <PostalCode>90292-6695</PostalCode>
      <StateProv>CA</StateProv>
    </Registrant>
    <TechnicalContact>
      <Email>abuse@iana.org</Email>
      <Name>Internet Corporation for Assigned Names and Number</Name>
      <Phone>+1-310-301-5820</Phone>
    </TechnicalContact>
    <UpdatedDate>2010-04-14</UpdatedDate>
    <ZoneContact i:nil="true"/>
  </RegistryData>
</WhoisRecord>

Я получаю:

  abuse@iana.orgInternet Corporation for Assigned Names and Number+1-310-301-5820,
    ,
    ,
    ,
    ...,      
    4676 Admiralty Way, Suite 330Marina del ReyUSInternet Assigned Numbers Authority90292-6695CA,      
    abuse@iana.orgInternet Corporation for Assigned Names and Number+1-310-301-5820,      
    2010-04-14,

Моя проблема заключается в том, что в результате преобразования отсутствуют узлы (например, элемент DomainName, содержащий IP-адрес), а некоторые дочерние узлы объединяются без запятых (как дочерние элементы AbuseContact).

Я бы хотел видеть все выходные данные XML в форме CSV и такие строки, как: "abuse@iana.orgInternet Corporation для присвоенных имен и номеров + 1-310-301-5820", разделенные запятыми.

Мой XSL довольно ржавый. Ваша помощь приветствуется. :)

Вот XSL, который я использую:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="iso-8859-1"/>

<xsl:strip-space elements="*" />

<xsl:template match="/*/child::*">
  <xsl:for-each select="child::*">
    <xsl:if test="position() != last()"><xsl:value-of select="normalize-space(.)"/>,    </xsl:if>
    <xsl:if test="position()  = last()"><xsl:value-of select="normalize-space(.)"/><xsl:text>&#xD;</xsl:text>
  </xsl:if>
  </xsl:for-each>
</xsl:template>

</xsl:stylesheet>

Ответы [ 2 ]

3 голосов
/ 17 мая 2010

Это простое преобразование дает желаемый результат :

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

    <xsl:template match="/">
    <xsl:apply-templates select="//text()"/>
    </xsl:template>

    <xsl:template match="text()">
      <xsl:copy-of select="."/>
      <xsl:if test="not(position()=last())">,</xsl:if>
    </xsl:template>
</xsl:stylesheet>

Примечание использование:

 <xsl:strip-space elements="*"/>

чтобы удалить любые текстовые узлы только для пробелов.

Обновление : AJ поднял проблему, заключающуюся в том, что результаты должны быть сгруппированы в повторы / кортежи на строку. В вопросе не определено, какой должна быть запись / кортеж. Поэтому текущее решение решает две проблемы текстовых узлов только для пробелов и пропущенных запятых, но не нацелено на вывод результатов в записи / кортежи.

0 голосов
/ 17 мая 2010

Я считаю, что вам нужно рекурсивное решение для решения этой проблемы. Итак, вам нужно что-то, что продолжает погружаться в дерево, пока оно не достигнет узла text (). Если этот узел text () фактически является дочерним по отношению к последнему узлу, он помещает новую строку. В противном случае он просто ставит значение с запятой.

Если узел не имеет узла text () в качестве своего потомка, то рекурсивно начинайте копаться в этом дереве.

<xsl:strip-space elements="*" />    

<xsl:template name="rec">        
    <xsl:param name="node"/>        
    <xsl:for-each select="child::*">
        <xsl:choose>
            <xsl:when test="child::text()">
                <xsl:choose>                        
                    <xsl:when test="local-name(.) != 'UpdatedDate'">"<xsl:value-of select="normalize-space(.)"/>", </xsl:when>
                    <xsl:otherwise>"<xsl:value-of select="normalize-space(.)"/>" <xsl:text>&#xD;</xsl:text></xsl:otherwise>
                </xsl:choose>                    
            </xsl:when>
            <xsl:when test="child::node()">
                <xsl:call-template name="rec">
                    <xsl:with-param name="node" select="child::node()"/>
                </xsl:call-template>                    
            </xsl:when>
        </xsl:choose>

    </xsl:for-each>
</xsl:template>

Это не доказательство глупости, но это дало мне результат с Саксонским концом:

"127.0.0.1", "abuse@iana.org", "Internet Corporation for Assigned Names and Number", "+1-310-301-5820", "...", "4676 Admiralty Way, Suite 330", "Marina del Rey", "US", "Internet Assigned Numbers Authority", "90292-6695", "CA", "abuse@iana.org", "Internet Corporation for Assigned Names and Number", "+1-310-301-5820", "2010-04-14"

Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...