3

我有一个要求将一个巨大的 XML文档转换为多个HTML文档。 的XML如下:XSLT - 适合任务吗?

<society> 
    <party_members> 
    <member id="1" first_name="" last_name="O'Brien"> 
     <ministry_id>1</ministry_id> 
     <ministry_id>3</ministry_id> 
    </member> 
    <member id="2" first_name="Julia" last_name=""> 
     <ministry_id>2</ministry_id> 
    </member> 
    <member id="3" first_name="Winston" last_name="Smith"> 
     <ministry_id>1</ministry_id> 
    </member> 
    </party_members> 
    <ministries> 
    <ministry> 
     <id>1</id> 
     <short_title>Minitrue</short_title> 
     <long_title>Ministry of truth</long_title> 
     <concerns>News, entertainment,education and arts </concerns>  
    </ministry> 
    <ministry> 
     <id>2</id> 
     <short_title>Minipax</short_title> 
     <long_title>Ministry of Peace</long_title> 
     <concerns>War</concerns> 
    </ministry> 
    <ministry> 
     <id>3</id> 
     <short_title>Minilove</short_title> 
     <long_title>Ministry of Love</long_title> 
     <concerns>Dissidents</concerns>  
    </ministry> 
    </ministries> 
</society> 

凡党员的潜在数量可能相当大 - 数以百万计,和各部委的数量少,在300-400家左右。对于每个党员应该有一个输出HTML与以下内容:

<html> 
    <body> 
    <h2>Party member: Winston Smith</h2> 
    <h3>Works in:</h3> 
    <div class="ministry"> 
     <h4>Ministry of truth</h4> - Minitrue 
     <h5>Ministry of truth <i>concerns</i> itself with <i>News, entertainment,education and arts</i></h5> 
    </div> 
    </body> 
</html> 

输出文件的数量应该==党员的数量。

我现在用XSLT挣扎,但不能让它开始工作。

请帮我决定,如果XSLT是这个工作的好工具,如果是,我的暗示,仿佛如何实现它,应该用什么XSLT结构等

当然,我可以简单地写但我正在寻找'应用转换模板'的方法,而不是程序分析和修改,以便能够将模板交给其他用户进行进一步修改(CSS,格式化等)。

我使用的红宝石+引入nokogiri(这是一组绑定到的libxslt),但也可以使用任何语言。

如果XSTL是一个坏适合这个任务,还有什么其他的仪器可以在这里使用,只要我必须几分钟的小内存占用变换用户的〜1M?

额外的好处是能够并行处理。

谢谢。

回答

2

为了实现这个结果(生产s几乎所有的html文件),你绝对需要XSLT 2.0。我建议撒克逊人的使用。

这里有产生你所需要的(会为每个成员一个HTML文件,都在你的系统正根了“HTML”文件夹内,并且还给它创造了什么报告)的样本XSL。您可能需要稍微微调一下以适应您的需求。

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes" method="html"/> 
    <xsl:variable name="target-dir" select="'/html'"/> 
    <xsl:key name="ministries" match="/society/ministries/ministry" use="id"/> 
    <xsl:strip-space elements="*"/> 
    <!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 
    <xsl:template match="/"> 
     <Output> 
      <xsl:apply-templates select="*"/> 
     </Output> 
    </xsl:template> 
    <!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 
    <xsl:template match="*"> 
     <xsl:apply-templates select="*"/> 
    </xsl:template> 
    <!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 
    <xsl:template match="member"> 
     <Html path="{concat($target-dir,'/',@id,'.html')}"> 
      <xsl:result-document href="{concat($target-dir,'/',@id,'.html')}"> 
       <html> 
        <body> 
        <h2><xsl:value-of select="concat('Party member: ',@first_name,' ',@last_name)"/></h2> 
        <h3>Works in:</h3> 
        <xsl:apply-templates select="ministry_id"/> 
        </body> 
       </html> 
      </xsl:result-document> 
     </Html> 
    </xsl:template> 
    <!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 
    <xsl:template match="ministry_id"> 
    <xsl:variable name="ministry" select="key('ministries',.)"/> 
    <div class="ministry"> 
     <h4><xsl:value-of select="$ministry/long_title"/></h4> - <xsl:value-of select="$ministry/short_title"/> 
     <h5><xsl:value-of select="$ministry/long_title"/> <i>concerns</i> itself with <i><xsl:value-of select="$ministry/concerns"/></i></h5> 
    </div> 
    </xsl:template> 
</xsl:stylesheet> 

在这里,你有一个输出样本:

<html> 
    <body> 
     <h2>Party member: O'Brien</h2> 
     <h3>Works in:</h3> 
     <div class="ministry"> 
     <h4>Ministry of truth</h4> - Minitrue 
     <h5>Ministry of truth<i>concerns</i> itself with <i>News, entertainment,education and arts </i></h5> 
     </div> 
     <div class="ministry"> 
     <h4>Ministry of Love</h4> - Minilove 
     <h5>Ministry of Love<i>concerns</i> itself with <i>Dissidents</i></h5> 
     </div> 
    </body> 
</html> 

关于性能,几百万的数据是一个大的量。我想这个xsl对于它来说已经够用了,但是我担心在确定之前你需要尝试一下。

我希望这可以帮助你!

+0

谢谢Carles,我会试试你的解决方案,并写一个更新什么工作,以及如何与简单的基准。 – Valentin

+0

嗨瓦伦丁,你设法给这个选项一试吗?我对基准测试结果很好奇 –

+0

嗨Carles,我只实现了一个简单的“概念验证”模板,撒克逊版本比libxml快4倍,现在我正在开发一个完整的模板,它是数千行,只要准备就绪,我会更新问题。 – Valentin

1

写你需要使用XSLT应该是简单的转变,但我不认为这是正确的技术要一次处理这么大的XML:它会在内存中加载整个数据和工作从那里,不对于这样一个大数据集来说,这是一件好事。

如果每个HTML文档都对应于整个文档的一个小连续部分,我建议使用程序拆分大XML文件(使用不会将整个文档加载到内存中的XML解析器),然后使用XSLT转换每件作品。

如果每个HTML文档包含来自文件和/或聚合的不同部分的数据(例如,符合某些条件的成员总数),我建议解析XML并将其数据加载到SQL数据库中,并且然后生成从该数据库读取的HTML文件。那么用纯XSLT 1.0

3

不能创建与你似乎想要做一个转换多个结果文档。对于您需要使用XSLT 2.0处理器等撒克逊9或AltovaXML与XSLT 2.0指令[xsl:result-document][1]或者需要使用XSLT 1.0处理器等xsltproc的/其中的libxslt实现http://www.exslt.org/exsl/elements/document/index.html。如果您可以使用其中之一,那么XSLT非常适合您的任务。

[编辑] 分别的libxslt xsltproc的下面的样式表代码

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:exsl="http://exslt.org/common" 
    exclude-result-prefixes="exsl" 
    extension-element-prefixes="exsl" 
    version="1.0"> 

<xsl:output method="html" indent="yes"/> 

<xsl:key name="ministry-by-id" match="ministry" use="id"/> 

<xsl:template match="/"> 
    <xsl:apply-templates select="society/party_members/member" mode="doc"/> 
</xsl:template> 

<xsl:template match="member" mode="doc"> 
    <exsl:document href="member{@id}.xml"> 
    <html> 
     <body> 
     <h2>Party member: <xsl:value-of select="concat(@first_name, ' ', @last_name)"/></h2> 
     <h3>Works in</h3> 
     <xsl:apply-templates select="key('ministry-by-id', ministry_id)"/> 
     </body> 
    </html> 
    </exsl:document> 
</xsl:template> 

<xsl:template match="ministry"> 
    <div class="ministry"> 
    <h4><xsl:value-of select="long_title"/></h4> 
    <h5><xsl:value-of select="long_title"/> <i>concerns</i> itself with <i><xsl:value-of select="concerns"/></i></h5> 
    </div> 
</xsl:template> 

</xsl:stylesheet> 

显示了如何使用exsl:document到输出几个结果文档与一个变换。它还使用密钥来提高性能。让我们知道该代码是否适用于您的巨大输入数据。

+0

我正在使用libxslt – Valentin

+0

'libxslt'应该能够完成创建多个结果文档的工作,当然对于任何XSLT任务来说,输入文档都会占用大量内存。 –

1

绝大多数工作都可以在XSLT 1.0中完成,但正如马丁所说,您只能生成一个包含所有HTML exerpt的文档。从这里,你可以使用XPath技术来选择每个html节点,并返回每个节点的OuterXml,供你写入文件/数据库等。

然而,处理所有党员可能并不可行立即由于内存限制。

由于党员对其他成员(只对部委)没有依赖性,所以我建议你一次处理党员1000人左右,所有部门都在XML文档中。您还可以将这些部分拆分为一个单独的xml文件,并在处理每个聚会成员xml文件期间使用xsl:document加载这些部委。

编辑xsl:document reference,和使用例如here

下面的XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       version="1.0" 
       > 

    <xsl:output method="xml" omit-xml-declaration="no" indent="yes" /> 

    <xsl:template match="/society"> 
     <root> 
      <xsl:apply-templates select="party_members/member" /> 
     </root> 
    </xsl:template> 

    <xsl:template match="member"> 
     <html> 
      <body> 
       <h2> 
        Party member: <xsl:value-of select="@first_name"/><xsl:text xml:space="preserve"> </xsl:text><xsl:value-of select="@last_name"/> 
       </h2> 
       <h3>Works in:</h3> 
       <div class="ministry"> 
        <xsl:for-each select="ministry_id"> 
         <xsl:variable name="ministryId" select="./text()" /> 
         <xsl:apply-templates select="/society/ministries/ministry[id=$ministryId]" mode="partymember"/> 
        </xsl:for-each> 
       </div> 
      </body> 
     </html> 
    </xsl:template> 

    <xsl:template match="ministry" mode="partymember"> 
     <h4> 
      <xsl:value-of select="long_title"/> 
     </h4> -  <xsl:value-of select="short_title"/> 
     <h5> 
      <xsl:value-of select="long_title"/><i>concerns</i> itself with <i> 
       <xsl:value-of select="concerns"/> 
      </i> 
     </h5> 
    </xsl:template> 

</xsl:stylesheet> 

产生以下输出(漂亮的印刷后):

<?xml version="1.0" encoding="utf-8"?> 
<root> 
    <html> 
     <body> 
      <h2> 
       Party member: O'Brien 
      </h2> 
      <h3>Works in:</h3> 
      <div class="ministry"> 
       <h4>Ministry of truth</h4> -  Minitrue<h5> 
        Ministry of truth<i>concerns</i> itself with <i>News, entertainment,education and arts </i> 
       </h5> 
      </div> 
     </body> 
    </html> 
    <html> 
     <body> 
      <h2> 
       Party member: Julia 
      </h2> 
      <h3>Works in:</h3> 
      <div class="ministry"> 
       <h4>Ministry of Peace</h4> -  Minipax<h5> 
        Ministry of Peace<i>concerns</i> itself with <i>War</i> 
       </h5><h4>Ministry of Love</h4> -  Minilove<h5> 
        Ministry of Love<i>concerns</i> itself with <i>Dissidents</i> 
       </h5> 
      </div> 
     </body> 
    </html> 
    <html> 
     <body> 
      <h2> 
       Party member: Winston Smith 
      </h2> 
      <h3>Works in:</h3> 
      <div class="ministry"> 
       <h4>Ministry of truth</h4> -  Minitrue<h5> 
        Ministry of truth<i>concerns</i> itself with <i>News, entertainment,education and arts </i> 
       </h5> 
      </div> 
     </body> 
    </html> 
</root> 
+0

谢谢@nonnb,请你分享一下外部链接文档的链接吗? – Valentin

+0

@ValentinVasilyev - 回复:为什么朱莉娅在2部 - 原来的xml没有部委id = 3(id = 2是重复的,因此朱莉娅有2个部) – StuartLC

+0

@ValentinVasilyev更新 – StuartLC

1

“巨​​大”有多大?如果有一百万名会员,我对撒克逊TinyTree的规模的猜测大概是100Mb,这在内存中确实是可行的。但是,你可能危险地接近不能进行主存转换的地步,然后你必须考虑流转换。

幸运的是,这并不能使XSLT无法使用,尽管它限制了您可能使用的XSLT处理器的范围。

Saxon-EE支持基于草稿XSLT 3的流式转换。0规范,但是,您通常必须以稍微不同的方式编写代码。在这个例子中,要使用流式传输,首先需要将“各部分”数据拆分为单独的文件 - 您可以使用两个结果文档将流式传输转换为流式转换。然后在主要转换中,您可以使用Carles Sala建议的密钥对“成员”数据进行流式处理,并对“部委”数据进行内存中处理。

Streaming XSLT是最尖端的技术,所以我们总是非常乐意帮助决定尝试的用户。