docb_edoc_xml_cb.erl

来自「OTP是开放电信平台的简称」· ERL 代码 · 共 1,155 行 · 第 1/3 页

ERL
1,155
字号
%% ``The contents of this file are subject to the Erlang Public License,%% Version 1.1, (the "License"); you may not use this file except in%% compliance with the License. You should have received a copy of the%% Erlang Public License along with this software. If not, it can be%% retrieved via the world wide web at http://www.erlang.org/.%%%% Software distributed under the License is distributed on an "AS IS"%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See%% the Licence for the specific language governing rights and limitations%% under the License.%%%% The Initial Developer of the Original Code is Ericsson AB.%% Portions created by Ericsson are Copyright 1999-2006, Ericsson AB.%% All Rights Reserved.创%%%%     $Id$%%-module(docb_edoc_xml_cb).%% This is the EDoc callback module for creating DocBuilder erlref%% documents (man pages) in XML format, and also a DocBuilder chapter%% document based on "overview.edoc".%%%% Usage examples:%%   docb_gen File%%   docb_gen -chapter overview.edoc%% or (from an Erlang shell)%% edoc:file(File, [{layout,docb_edoc_xml_cb},{file_suffix,".xml"},%%                  {preprocess,true}]).%%%% The origin of this file is the edoc module otpsgml_layout.erl%% written by Richard Carlsson.-export([module/2, overview/2]).-include("xmerl.hrl").-define(NL, "\n").%%-User interface-------------------------------------------------------%% ERLREFmodule(Element, _Opts) ->    XML = layout_module(Element),    xmerl:export_simple([XML], docb_xmerl_xml_cb, []).%% CHAPTERoverview(Element, _Opts) ->    XML = layout_chapter(Element),    xmerl:export_simple([XML], docb_xmerl_xml_cb, []).%%--Internal functions--------------------------------------------------layout_module(#xmlElement{name = module, content = Es}=E) ->    Name = get_attrval(name, E),    Desc = get_content(description, Es),    ShortDesc = text_only(get_content(briefDescription, Desc)),    FullDesc =  otp_xmlify(get_content(fullDescription, Desc)),    Types0 = get_content(typedecls, Es),    Types1 = lists:sort([{type_name(Et), Et} || Et <- Types0]),    Functions = [Ef || Ef <- get_content(functions, Es)],    SortedFs = lists:sort([{function_name(Ef), Ef} || Ef <- Functions]),    Header = {header, [		       ?NL,{title, [Name]},		       ?NL,{prepared, [""]},		       ?NL,{responsible, [""]},		       ?NL,{docno, ["1"]},		       ?NL,{approved, [""]},		       ?NL,{checked, [""]},		       ?NL,{date, [""]},		       ?NL,{rev, ["A"]},		       ?NL,{file, [Name++".xml"]}		      ]},    Module = {module, [Name]},    ModuleSummary = {modulesummary, ShortDesc},    Description = {description, [?NL|FullDesc]},    Types = case Types1 of		[] -> [];		_ ->		    [?NL, {section,[{title,["DATA TYPES"]},				    {marker,[{id,"types"}],[]},				    ?NL|types(Types1)]}]	    end,    Funcs = functions(SortedFs),    See = seealso_module(Es),    Authors = {authors, authors(Es)},    {erlref,     [?NL,Header,      ?NL,Module,      ?NL,ModuleSummary,      ?NL,Description]     ++ Types ++     [?NL,Funcs,      ?NL,See,      ?NL,Authors]    }.layout_chapter(#xmlElement{name=overview, content=Es}) ->    Title = get_text(title, Es),    Header = {header, [		       ?NL,{title,[Title]},		       ?NL,{prepared,[""]},		       ?NL,{docno,[""]},		       ?NL,{date,[""]},		       ?NL,{rev,[""]}		      ]},    DescEs = get_content(description, Es),    FullDescEs = get_content(fullDescription, DescEs),    Sections = chapter_ify(FullDescEs, first),    {chapter, [?NL, Header, ?NL | Sections]}.chapter_ify([], _) ->    [];chapter_ify(Es, first) ->    %% Everything up to the first section should be made into    %% plain paragraphs -- or if no first section is found, everything    %% should be made into one    case find_next(h3, Es) of	{Es, []} ->	    SubSections = subchapter_ify(Es, first),	    [{section, [?NL,{title,["Overview"]},			?NL | SubSections]}];	{FirstEs, RestEs} ->	    otp_xmlify(FirstEs) ++ chapter_ify(RestEs, next)    end;chapter_ify([#xmlElement{name=h3} = E | Es], next) ->    {SectionEs, RestEs} = find_next(h3, Es),    SubSections = subchapter_ify(SectionEs, first),    {Marker, Title} = chapter_title(E),    [{section, [?NL,{marker,[{id,Marker}],[]},		?NL,{title,[Title]},		?NL | SubSections]} | chapter_ify(RestEs, next)].subchapter_ify([], _) ->    [];subchapter_ify(Es, first) ->    %% Everything up to the (possible) first subsection should be    %% made into plain paragraphs    {FirstEs, RestEs} = find_next(h4, Es),    otp_xmlify(FirstEs) ++ subchapter_ify(RestEs, next);subchapter_ify([#xmlElement{name=h4} = E | Es], next) ->    {SectionEs, RestEs} = find_next(h4, Es),    Elements = otp_xmlify(SectionEs),    {Marker, Title} = chapter_title(E),    [{section, [?NL,{marker,[{id,Marker}],[]},		?NL,{title,[Title]},		?NL | Elements]} | subchapter_ify(RestEs, next)].chapter_title(#xmlElement{content=Es}) -> % name = h3 | h4    case Es of	[#xmlElement{name=a} = E] ->	    {get_attrval(name, E), get_text(E)}    end.%%--XHTML->XML transformation-------------------------------------------%% otp_xmlify(Es1) -> Es2%%   Es1 = Es2 = [#xmlElement{} | #xmlText{}]%% Fix things that are allowed in XHTML but not in chapter/erlref DTDs.%% 1)  lists (<ul>, <ol>, <dl>) and code snippets (<pre>) can not occur%%     within a <p>, such a <p> must be splitted into a sequence of <p>,%%     <ul>, <ol>, <dl> and <pre>.%% 2)  <a> must only have either a href attribute (corresponds to a%%     <seealso> or <url> in the XML code) in which case its content%%     must be plain text; or a name attribute (<marker>).%% 3a) <b> content must be plain text.%%  b) <em> content must be plain text (or actually a <code> element%%     as well, but a simplification is used here).%%  c) <pre> content must be plain text (or could actually contain%%     <input> as well, but a simplification is used here).%% 4)  <code> content must be plain text, or the element must be split%%     into a list of elements.%% 5a) <h1>, <h2> etc is not allowed - replaced by its content within%%     a <b> tag.%%  b) <center> is not allowed - replaced by its content.%%  c) <font>   -"-%% 6)  <table> is not allowed in erlref, translated to text instead.%%     Also a <table> in chapter without a border is translated to text.%%     A <table> in chapter with a border must contain a <tcaption>.%% 7)  <sup> is not allowed - is replaced with its text content%%     within parenthesis.%% 8)  <blockquote> contents may need to be made into paragraphs%% 9)  <th> (table header) is not allowed - is replaced by%%     <td><em>...</em></td>.otp_xmlify([]) ->    [];otp_xmlify(Es0) ->    Es = case is_paragraph(hd(Es0)) of	     %% If the first element is a <p> xmlElement, then	     %% the entire element list is ready to be otp_xmlified.	     true ->		 Es0;	     %% If the first element is not a <p> xmlElement, then all	     %% elements up to the first <p> (or end of list) must be	     %% made into a paragraph (using the {p, Es} construction)	     %% before the list is otp_xmlified.	     false ->		 case find_next(p, Es0, []) of		     {[#xmlText{value=Str}] = First, Rest} ->			 %% Special case: Making a paragraph out of a			 %% blank line isn't a great idea.			 case is_empty(Str) of			     true ->				 Rest;			     false ->				 [{p,First}|Rest]			 end;		     {First, Rest} ->			 [{p,First}|Rest]		 end	 end,    %% Fix paragraph breaks not needed in XHTML but in XML    EsFixed = otp_xmlify_fix(Es),    otp_xmlify_es(EsFixed).%% EDoc does not always translate empty lines (with leading "%%")%% as paragraph break, this is the fixotp_xmlify_fix(Es) ->    otp_xmlify_fix(Es, []).otp_xmlify_fix([#xmlText{value="\n \n"++_} = E1, E2 | Es], Res) ->    %% This is how it looks when generating an erlref from a .erl file    case is_paragraph(E2) of	false ->	    {P, After} = find_p_ending(Es, []),	    otp_xmlify_fix(After, [{p, [E2|P]}, E1 | Res]);	true ->	    otp_xmlify_fix([E2|Es], [E1|Res])    end;otp_xmlify_fix([#xmlText{value="\n\n"} = E1, E2 | Es], Res) ->    %% This is how it looks when generating a chapter from overview.edoc    case is_paragraph(E2) of	false ->	    {P, After} = find_p_ending(Es, []),	    otp_xmlify_fix(After, [{p, [E2|P]}, E1 | Res]);	true ->	    otp_xmlify_fix([E2|Es], [E1|Res])    end;otp_xmlify_fix([E|Es], Res) ->    otp_xmlify_fix(Es, [E|Res]);otp_xmlify_fix([], Res) ->    lists:reverse(Res).otp_xmlify_es([E | Es]) ->    case is_paragraph(E) of	true ->	    case otp_xmlify_psplit(E) of		%% paragraph contained inline tags and text only		nosplit ->		    otp_xmlify_e(E) ++ otp_xmlify_es(Es);		%% paragraph contained dl, ul and/or pre and has been		%% splitted		SubEs ->		    lists:flatmap(fun otp_xmlify_e/1, SubEs) ++			otp_xmlify_es(Es)	    end;	false ->	    otp_xmlify_e(E) ++ otp_xmlify_es(Es)    end;otp_xmlify_es([]) ->    [].%% otp_xmlify_psplit(P) -> nosplit | [E]%% Handles case 1) above.%% Uses the {p, Es} construct, thus replaces an p xmlElement with one%% or more {p, Es} tuples if splitting the paraghrap is necessary.otp_xmlify_psplit(P) ->    otp_xmlify_psplit(p_content(P), [], []).otp_xmlify_psplit([#xmlElement{name=Name}=E | Es], Content, Res) ->    if	Name==blockquote; Name==ul; Name==ol; Name==dl; Name==pre;	Name==table ->	    case Content of		[] ->		    otp_xmlify_psplit(Es, [], [E|Res]);		[#xmlText{value=Str}] ->		    %% Special case: Making a paragraph out of a blank		    %% line isn't a great idea. Instead, this can be		    %% viewed as the case above, where there is no		    %% content to make a paragraph out of		    case is_empty(Str) of			true ->			    otp_xmlify_psplit(Es, [], [E|Res]);			false ->			    Pnew = {p, lists:reverse(Content)},			    otp_xmlify_psplit(Es, [], [E,Pnew|Res])		    end;		_ ->		    Pnew = {p, lists:reverse(Content)},		    otp_xmlify_psplit(Es, [], [E,Pnew|Res])	    end;	true ->	    otp_xmlify_psplit(Es, [E|Content], Res)    end;otp_xmlify_psplit([E | Es], Content, Res) ->    otp_xmlify_psplit(Es, [E|Content], Res);otp_xmlify_psplit([], _Content, []) ->    nosplit;otp_xmlify_psplit([], [], Res) ->    lists:reverse(Res);otp_xmlify_psplit([], [#xmlText{value="\n\n"}], Res) ->    lists:reverse(Res);otp_xmlify_psplit([], Content, Res) ->    Pnew = {p, lists:reverse(Content)},    lists:reverse([Pnew|Res]).%% otp_xmlify_e(E) -> [E]%% This is the function which does the actual transformation of%% single elements, normally by making sure the content corresponds%% to what is allowed by the OTP DTDs.%% Returns a list of elements as the xmlification in some cases%% returns no element or more than one element (although in most cases%% exactly one element).otp_xmlify_e(#xmlElement{name=a} = E) ->       % 2) above    otp_xmlify_a(E);otp_xmlify_e(#xmlElement{name=Tag} = E)        % 3a-c)  when Tag==b; Tag==em; Tag==pre ->    Content = text_only(E#xmlElement.content),    [E#xmlElement{content=Content}];otp_xmlify_e(#xmlElement{name=code} = E) ->    % 4)    case catch text_only(E#xmlElement.content) of	{'EXIT', _Error} ->	    otp_xmlify_code(E);	Content ->	    [E#xmlElement{content=Content}]    end;otp_xmlify_e(#xmlElement{name=Tag} = E)        % 5a  when Tag==h1; Tag==h2; Tag==h3; Tag==h4; Tag==h5;       Tag==center;       Tag==font ->    Content = text_only(E#xmlElement.content),    [E#xmlElement{name=b, content=Content}];otp_xmlify_e(#xmlElement{name=Tag} = E)        % 5b-c)  when Tag==center;       Tag==font ->    otp_xmlify_e(E#xmlElement.content);otp_xmlify_e(#xmlElement{name=table} = E) ->   % 6)    case parent(E) of	module ->	    otp_xmlify_table(E#xmlElement.content);	overview ->	    case get_attrval(border, E) of		"" -> % implies border="0"		    [{p, otp_xmlify_table(E#xmlElement.content)}];		"0" ->		    [{p, otp_xmlify_table(E#xmlElement.content)}];		_Val ->		    Content0 = otp_xmlify_e(E#xmlElement.content),		    Summary = #xmlText{value=get_attrval(summary, E)},		    TCaption = E#xmlElement{name=tcaption,					    attributes=[],					    content=[Summary]},		    Content = Content0 ++ [TCaption],		    [E#xmlElement{attributes=[], content=Content}]	    end    end;otp_xmlify_e(#xmlElement{name=sup} = E) ->     % 7)    Text = get_text(E),    [#xmlText{parents = E#xmlElement.parents,	      pos = E#xmlElement.pos,	      language = E#xmlElement.language,	      value = "(" ++ Text ++ ")"}];otp_xmlify_e(#xmlElement{name=blockquote} = E) -> % 8)    Content = otp_xmlify_blockquote(E#xmlElement.content),    [E#xmlElement{content=Content}];otp_xmlify_e(#xmlElement{name=th} = E) ->      % 9)    Content = otp_xmlify_e(E#xmlElement.content),    EmE = E#xmlElement{name=em, content=Content},    [E#xmlElement{name=td, content=[EmE]}];otp_xmlify_e(#xmlElement{name=p} = E) ->       % recurse    Content = otp_xmlify_e(E#xmlElement.content),    [E#xmlElement{content=Content}];otp_xmlify_e({p, Content1}) ->    Content2 = otp_xmlify_e(Content1),    [{p, Content2}];otp_xmlify_e(#xmlElement{name=ul} = E) ->    Content = otp_xmlify_e(E#xmlElement.content),    [E#xmlElement{content=Content}];otp_xmlify_e(#xmlElement{name=li} = E) ->

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?