我有一个庞大而复杂的XML文档,需要使用XSLT进行两次转换才能获得所需的结果。感谢michael's answer here,我在本地运行转换(在终端上使用xsltproc)时可以完美地工作,但是我现在无法以相同的方式工作,因为我已经移动了它到PHP。
源文档的重要部分如下所示:
<BiographicalNote>
<p>This text includes escaped HTML entities.</p>
</BiographicalNote>
所需的输出:
<ParagraphStyleRange>
<CharacterStyleRange>
<Content>
This text includes escaped HTML entities.
</Content>
</CharacterStyleRange>
</ParagraphStyleRange>
我需要分两步进行这种转换,因为我需要取消HTML实体的转换,然后将它们作为XML处理以应用进一步的转换。因此,第一步处理大部分转换,设置结束文档,但是当涉及到HTML部分时,只会这样做:
<xsl:template match="BiographicalNote">
<AuthorBio>
<xsl:value-of select="normalize-space(.)" disable-output-escaping="yes" />
</AuthorBio>
</xsl:template>
然后我有第二个XSLT来摆脱<p>
标签并使用<em>
,<b>
和<span>
标签进行各种其他转换:
<xsl:template match="AuthorBio">
<ParagraphStyleRange>
<xsl:apply-templates select="./node()"/>
<Br/>
</ParagraphStyleRange>
</xsl:template>
<xsl:template match="p/text()|text()"> <!-- Not all HTML paragraphs have actual <p> tags. -->
<CharacterStyleRange>
<Content><xsl:value-of select="."/></Content>
</CharacterStyleRange>
</xsl:template>
正如我上面提到的,当我使用xsltproc在本地转换它时,这非常有效。但是使用PHP,我得到的是:
<ParagraphStyleRange>
<CharacterStyleRange>
<Content>
<p>This text includes escaped HTML entities.</p>
</Content>
</CharacterStyleRange>
</ParagraphStyleRange>
我已尝试过PHP代码的一些变体,但这就是我最接近的原因:
function processONIX () {
// Load ONIX file
$onix = new DOMDocument;
$onix->load( 'HarbourONIX20141217.xml' );
// Load ONIXtoICML XSL file
$icml = new DOMDocument;
$icml->load( 'ONIXtoICML.xsl' );
// Configure the transformer
$icmlproc = new XSLTProcessor;
$icmlproc->importStyleSheet($icml);
// Apply ONIXtoICML
return $icmlproc->transformToDoc($onix);
}
function makeICML () {
$temp = processONIX();
// Load Inlines XSL file
$inline = new DOMDocument;
$inline->load( 'Inlines.xsl' );
// Configure the transformer
$inlineproc = new XSLTProcessor;
$inlineproc->importStyleSheet($inline);
// Apply Inlines
$inlineproc->transformToURI($temp, 'ONIX.icml');
}
makeICML();
<AuthorBio><p>This text includes escaped HTML entities.</p></AuthorBio>
但是当我尝试将其作为makeICML()中的新DOMDocument加载时(与processONIX()中的方式相同)似乎加载为一个空文档。不知道这里发生了什么。问题似乎出现在makeICML()函数中,但这看起来很奇怪,因为它与processONIX()几乎完全相同,只有不同的变量和文件名。我无法弄清楚角色何时被逃脱,所以:我该如何防止呢?
答案 0 :(得分:1)
disable-output-escaping属性是序列化程序的指令,除非您序列化转换的输出,即将其转换为词法XML,否则它不起作用。在第一次转换中,您使用的是transformToDoc(),它将输出创建为内存中的树,绕过序列化步骤。所以disable-output-escaping没有效果。
答案 1 :(得分:0)
在代码中未与您的问题共享的部分中必须有一些错误,如同给定源XML一样:
$source = <<<XML
<source>
<BiographicalNote>
<p>This text includes escaped HTML entities.</p>
</BiographicalNote>
</source>
XML;
并给出第一个样式表:
$xsltA = <<<XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="BiographicalNote">
<AuthorBio>
<xsl:value-of select="normalize-space(.)" disable-output-escaping="yes" />
</AuthorBio>
</xsl:template>
</xsl:stylesheet>
XSLT;
并给出第二个样式表:
$xsltB = <<<XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="AuthorBio">
<ParagraphStyleRange>
<xsl:apply-templates select="./node()"/>
<Br/>
</ParagraphStyleRange>
</xsl:template>
<xsl:template match="p/text()|text()"> <!-- Not all HTML paragraphs have actual <p> tags. -->
<CharacterStyleRange>
<Content><xsl:value-of select="."/></Content>
</CharacterStyleRange>
</xsl:template>
</xsl:stylesheet>
XSLT;
执行申请:
echo $source2 = Proc::create($xsltA)->transform($source), "\n----\n";
echo $source3 = Proc::create($xsltB)->transform($source2), "\n";
以下美化输出的结果:
<AuthorBio><p>This text includes escaped HTML entities.</p></AuthorBio>
----
<ParagraphStyleRange>
<CharacterStyleRange>
<Content>This text includes escaped HTML entities.</Content>
</CharacterStyleRange>
<Br/>
</ParagraphStyleRange>
完整的示例代码:
<?php
/**
* http://stackoverflow.com/questions/27751339/how-do-i-prevent-character-escaping-in-php-xslt
*/
/**
* Class Proc
*
* XSLT Processor
*/
class Proc
{
private $proc;
/**
* @param string $xslt
*
* @return Proc
*/
public static function create($xslt)
{
return new self($xslt);
}
public function __construct($xslt)
{
$proc = new XSLTProcessor();
$proc->importStylesheet(
$this->docFromString($xslt)
);
$this->proc = $proc;
}
public function transform($source)
{
$result = $this->proc->transformToDoc(
$this->docFromString($source)
);
$result->formatOutput = true;
$result->preserveWhiteSpace = false;
return $result->saveXML($result->documentElement);
}
private function docFromString($string)
{
$doc = new DOMDocument();
$doc->loadXML($string);
return $doc;
}
}
$source = <<<XML
<source>
<BiographicalNote>
<p>This text includes escaped HTML entities.</p>
</BiographicalNote>
</source>
XML;
$xsltA = <<<XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="BiographicalNote">
<AuthorBio>
<xsl:value-of select="normalize-space(.)" disable-output-escaping="yes" />
</AuthorBio>
</xsl:template>
</xsl:stylesheet>
XSLT;
$xsltB = <<<XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="AuthorBio">
<ParagraphStyleRange>
<xsl:apply-templates select="./node()"/>
<Br/>
</ParagraphStyleRange>
</xsl:template>
<xsl:template match="p/text()|text()"> <!-- Not all HTML paragraphs have actual <p> tags. -->
<CharacterStyleRange>
<Content><xsl:value-of select="."/></Content>
</CharacterStyleRange>
</xsl:template>
</xsl:stylesheet>
XSLT;
echo $source2 = Proc::create($xsltA)->transform($source), "\n----\n";
echo $source3 = Proc::create($xsltB)->transform($source2), "\n";