有没有办法修改样式表,以便它将带有空标记的 XML 文档转换为 <tag />?

Is there a way to modify the style sheet so that it transforms an XML document with empty tags as <tag />?

本文关键字:文档 转换 XML lt gt tag 样式 修改 有没有      更新时间:2023-10-16

我从代码项目中提取了一些代码来重新缩进XML文档。 有谁知道我如何修改样式表以使其使XML文件的转换将导致空标签显示为<tag />而不是<tag></tag>

// http://www.codeproject.com/Articles/43309/How-to-create-a-simple-XML-file-using-MSXML-in-C
MSXML2::IXMLDOMDocumentPtr FormatDOMDocument(MSXML2::IXMLDOMDocumentPtr pDoc)
{
    LPCSTR const static szStyleSheet =
        R"!(<?xml version="1.0" encoding="utf-8"?>)!"
        R"!(<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">)!"
        R"!(    <xsl:output method="xml" indent="yes"/>)!"
        R"!(    <xsl:template match="@* | node()">)!"
        R"!(        <xsl:copy>)!"
        R"!(            <xsl:apply-templates select="@* | node()"/>)!"
        R"!(        </xsl:copy>)!"
        R"!(    </xsl:template>)!"
        R"!(</xsl:stylesheet>)!";
    MSXML2::IXMLDOMDocumentPtr pXmlStyleSheet;
    pXmlStyleSheet.CreateInstance(__uuidof(MSXML2::DOMDocument60));
    pXmlStyleSheet->loadXML(szStyleSheet);
    MSXML2::IXMLDOMDocumentPtr pXmlFormattedDoc;
    pXmlFormattedDoc.CreateInstance(__uuidof(MSXML2::DOMDocument60));
    CComPtr<IDispatch> pDispatch;
    HRESULT hr = pXmlFormattedDoc->QueryInterface(IID_IDispatch, (void**)&pDispatch);
    if (SUCCEEDED(hr))
    {
        _variant_t    vtOutObject;
        vtOutObject.vt = VT_DISPATCH;
        vtOutObject.pdispVal = pDispatch;
        vtOutObject.pdispVal->AddRef();
        hr = pDoc->transformNodeToObject(pXmlStyleSheet, vtOutObject);
    }
    //By default it is writing the encoding = UTF-16. Let us change the encoding to UTF-8
    // <?xml version="1.0" encoding="UTF-8"?>
    MSXML2::IXMLDOMNodePtr pXMLFirstChild = pXmlFormattedDoc->GetfirstChild();
    // A map of the a attributes (vesrsion, encoding) values (1.0, UTF-8) pair
    MSXML2::IXMLDOMNamedNodeMapPtr pXMLAttributeMap =  pXMLFirstChild->Getattributes();
    MSXML2::IXMLDOMNodePtr pXMLEncodNode = pXMLAttributeMap->getNamedItem(_T("encoding"));
    pXMLEncodNode->PutnodeValue(_T("UTF-8"));    //encoding = UTF-8
    return pXmlFormattedDoc;
}

此样式表会导致尽可能写入空标记(使用 MSXML6):

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[not(*) and not(normalize-space()) and not(comment()) and not(processing-instruction())]">
        <xsl:element name="{name()}" namespace="{namespace-uri()}">
            <xsl:copy-of select="./@*"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

这是通过避免对没有子元素、文本、注释或处理指令的元素进行xsl:copy,并使用 xsl:element "手动"复制元素来实现的。请注意,属性也会与嵌套xsl:copy-of一起复制。

例如,此 XML 文档:

<Document>
<empty> </empty>
<empty-2/>
<non-empty>
Some text
</non-empty>
<non-empty-2 some-attribute="attribute text">
<empty-3/>
<non-empty-3><empty-4/><empty-with-attribute another-attribute="some more text">    

</empty-with-attribute>
</non-empty-3>
</non-empty-2>
<abc:non-empty-with-namespace xmlns:abc="urn:test:abc">
<abc:empty-with-namespace abc:namespaced-attribute="namespaced attribute text"/>
</abc:non-empty-with-namespace>
<non-empty-comment>
<!-- A comment -->
</non-empty-comment>
<non-empty-proc-instr>
<?some-instruction?>
</non-empty-proc-instr>
</Document>

将使用 FormatDOMDocument 函数使用更新的样式表转换为以下内容:

<?xml version="1.0" encoding="UTF-8"?>
<Document>
    <empty/>
    <empty-2/>
    <non-empty>
Some text
</non-empty>
    <non-empty-2 some-attribute="attribute text">
        <empty-3/>
        <non-empty-3>
            <empty-4/>
            <empty-with-attribute another-attribute="some more text"/>
        </non-empty-3>
    </non-empty-2>
    <abc:non-empty-with-namespace xmlns:abc="urn:test:abc">
        <abc:empty-with-namespace abc:namespaced-attribute="namespaced attribute text"/>
    </abc:non-empty-with-namespace>
    <non-empty-comment>
        <!-- A comment -->
    </non-empty-comment>
    <non-empty-proc-instr>
        <?some-instruction?>
    </non-empty-proc-instr>
</Document>

要按名称将空标签限制为仅某些元素,您可以调整match模式以添加对元素名称的检查:contains('|list|of|element|names|', concat('|',name(),'|')) 。请注意,该名称列表用 | 分隔,并且在列表的开头和结尾也有一个|,我们也将元素名称与这些分隔符连接起来。这个技巧使我们能够使用contains(只匹配任何子字符串)来实现在列表中搜索的效果。

例如,在我前面的示例中,允许non-emptyempty-2empty-4abc:empty-with-namespace元素的空标签,更新后的样式表将是:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" indent="yes"/>
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="*[contains('|non-empty|empty-2|empty-4|abc:empty-with-namespace|',  concat('|',name(),'|')) and not(*) and not(normalize-space()) and not(comment()) and not(processing-instruction())]">
        <xsl:element name="{name()}" namespace="{namespace-uri()}">
            <xsl:copy-of select="./@*"/>
        </xsl:element>
    </xsl:template>
</xsl:stylesheet>

FormatDOMDocument的输出将变为:

<?xml version="1.0" encoding="UTF-8"?>
<Document>
    <empty></empty>
    <empty-2/>
    <non-empty>
Some text
</non-empty>
    <non-empty-2 some-attribute="attribute text">
        <empty-3></empty-3>
        <non-empty-3>
            <empty-4/>
            <empty-with-attribute another-attribute="some more text"></empty-with-attribute>
        </non-empty-3>
    </non-empty-2>
    <abc:non-empty-with-namespace xmlns:abc="urn:test:abc">
        <abc:empty-with-namespace abc:namespaced-attribute="namespaced attribute text"/>
    </abc:non-empty-with-namespace>
    <non-empty-comment>
        <!-- A comment -->
    </non-empty-comment>
    <non-empty-proc-instr>
        <?some-instruction?>
    </non-empty-proc-instr>
</Document>

请注意,尽管我们将non-empty指定为该列表中的可能空标记,但它不会显示为空,因为它实际上有一个文本节点(这是我们想要的)。另外,请注意,empty不在我们的列表中,并且它带有一个结束标记作为<empty></empty>这也是我们在这种情况下想要的(同样适用于empty-3)。