【问题标题】:Extract part of an XML file as plain text using XSLT使用 XSLT 将 XML 文件的一部分提取为纯文本
【发布时间】:2011-06-18 10:28:55
【问题描述】:

看起来这应该很容易,但是...

我正在尝试使用 XSLT 将 XML 文件的一部分提取为纯文本,丢弃其余部分。

所以从这样的示例输入中......

<?xml version="1.0" encoding="UTF-8"?>
<?oxygen RNGSchema="http://segonku.unl.edu/teianalytics/TEIAnalytics.rng"
                        type="xml"?>
<TEI xmlns="http://www.tei-c.org/ns/1.0" n="Wright2-0034.sgml.xml">
   <teiHeader type="text">
      <fileDesc>
         <titleStmt>
            <title>Header Title</title>
         </titleStmt>
         <publicationStmt>
            <p>Published</p>
         </publicationStmt>
         <sourceDesc>
            <p>Sourced</p>
         </sourceDesc>
      </fileDesc>
   </teiHeader>
   <text>
      <front>
      </front>
      <body>
         <head>THE TITLE</head>
         <div type="chapter" part="N" org="uniform" sample="complete">
            <head>CHAPTER I</head>
            <p>Some text.</p>
         </div>
      </body>
   </text>
</TEI>

...我正在尝试获取包含在 &lt;body&gt; 标签及其所有子标签中的文本。在这种情况下,所需的输出是:

THE TITLE
CHAPTER I
Some text.

潜在的并发症:&lt;body&gt; 也可以存在于&lt;front&gt; 问题和/或&lt;teiHeader&gt; 中,所以我真正需要的是&lt;body&gt; 的子代当且仅当该标签是@ 的子代987654328@ 和&lt;TEI&gt;

我已经尝试过像这样非常简单的 XSL ...

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="text"/>
    <xsl:template match="/TEI/text/body">
        <xsl:apply-templates select="."/>
    </xsl:template>
</xsl:stylesheet>

...但它为我提供了文件中所有内容的纯文本,而不仅仅是 &lt;body&gt; 元素。

谢谢!

【问题讨论】:

  • 好问题,+1。有关问题的解释以及完整、简短且简单的解决方案,请参阅我的答案。
  • 您是否知道您将在 inline 元素、表格和列表中遇到的麻烦?您需要管理这些吗?
  • @empo 好点。幸运的是,我不需要为我的用例担心。

标签: xml xslt


【解决方案1】:

我尝试过像这样非常简单的 XSL ...

...

     <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 version="1.0">
         <xsl:output method="text"/>
         <xsl:template match="/TEI/text/body">
             <xsl:apply-templates select="."/>
         </xsl:template>
     </xsl:stylesheet>

...但它给了我纯文本 文件中的所有内容,而不仅仅是 &lt;body&gt; 元素。

其原因是 XPath 的一个著名属性/功能(以及成千上万类似问题的原因)将任何无前缀名称视为属于“无命名空间”。但是,所提供的 XML 文档中的任何元素都属于命名空间: “http://www.tei-c.org/ns/1.0”,并且必须作为此命名空间中的节点访问。

解决方案:在 XSLT 代码中定义文档默认命名空间(这次绑定了前缀)并在指定每个名称时使用前缀。

这是产生所需结果的最简单和最短的转换之一

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

 <xsl:template match="x:text/x:body//text()">
  <xsl:value-of select="concat(.,'&#xA;')"/>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

应用于提供的 XML 文档时

<TEI xmlns="http://www.tei-c.org/ns/1.0" n="Wright2-0034.sgml.xml">
    <teiHeader type="text">
        <fileDesc>
            <titleStmt>
                <title>Header Title</title>
            </titleStmt>
            <publicationStmt>
                <p>Published</p>
            </publicationStmt>
            <sourceDesc>
                <p>Sourced</p>
            </sourceDesc>
        </fileDesc>
    </teiHeader>
    <text>
        <front>      </front>
        <body>
            <head>THE TITLE</head>
            <div type="chapter" part="N" org="uniform" sample="complete">
                <head>CHAPTER I</head>
                <p>Some text.</p>
            </div>
        </body>
    </text>
</TEI>

产生想要的正确结果

THE TITLE
CHAPTER I
Some text.

【讨论】:

  • +1 得到很好的解释(确实是正确的答案)。请注意,这种方法为每个文本后代节点添加了一个换行符。这对于body 内的inline 元素或列表可能是不需要的。即使没有 OP 提到这一点,当尝试将类似 HTML 的标记转换为纯文本时,这也是一个真正常见的问题。更不用说表格的情况了:))
  • @empo:OP 希望每个文本节点在输出中的新行开始——而不是它们被连接起来。
  • 太棒了!是的,这是完美的。感谢您的解释;我很高兴知道我在最初的尝试中遗漏了什么。 +1 并接受回答。
【解决方案2】:

你可以使用:

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

<xsl:template match="/" xmlns:n="http://www.tei-c.org/ns/1.0">
    <xsl:for-each select="/n:TEI/n:text/n:body/descendant::*/text()">
        <xsl:value-of select="."/>
        <xsl:if test="position() != last()">
            <xsl:text>&#xa;</xsl:text>
        </xsl:if>
    </xsl:for-each>
</xsl:template>

返回:

THE TITLE
CHAPTER I
Some text.

【讨论】:

  • 不过,他需要确保 /TEI/text/body 路径。
  • 我最好在根 XSLT 元素中声明命名空间。如果您有更多模板,您会对此感到疯狂。
【解决方案3】:

尝试匹配 /TEI/text/body//text()

【讨论】:

  • 对不起,伙计,这是错误的建议——请参阅我的答案以获得解释。
猜你喜欢
  • 2021-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-30
相关资源
最近更新 更多